diff --git a/dl/mt7981_conninfra_20220425-bbf588-obj.tar.xz b/dl/mt7981_conninfra_20220425-bbf588-obj.tar.xz deleted file mode 100644 index 842f956244..0000000000 Binary files a/dl/mt7981_conninfra_20220425-bbf588-obj.tar.xz and /dev/null differ diff --git a/dl/mt7986_conninfra-bbf588-obj.tar.xz b/dl/mt7986_conninfra-bbf588-obj.tar.xz deleted file mode 100644 index ada92e5616..0000000000 Binary files a/dl/mt7986_conninfra-bbf588-obj.tar.xz and /dev/null differ diff --git a/package/mtk/drivers/conninfra/Makefile b/package/mtk/drivers/conninfra/Makefile index 8b731ae804..17db624d49 100644 --- a/package/mtk/drivers/conninfra/Makefile +++ b/package/mtk/drivers/conninfra/Makefile @@ -9,15 +9,6 @@ include $(TOPDIR)/rules.mk include $(INCLUDE_DIR)/kernel.mk PKG_NAME:=conninfra - -ifeq ($(CONFIG_MTK_CONNINFRA_APSOC_MT7981),y) -PKG_SOURCE:=mt7981_conninfra_20220425-bbf588-obj.tar.xz -else -ifeq ($(CONFIG_MTK_CONNINFRA_APSOC_MT7986),y) -PKG_SOURCE:=mt7986_conninfra-bbf588-obj.tar.xz -endif -endif - PKG_VERSION:=bbf588 PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME) PKG_MAINTAINER:=Kun-Ze Syue diff --git a/package/mtk/drivers/conninfra/src/Makefile b/package/mtk/drivers/conninfra/src/Makefile new file mode 100644 index 0000000000..b0a81db708 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/Makefile @@ -0,0 +1,66 @@ +############################################################################### +# Necessary Check + +#ifeq ($(AUTOCONF_H),) +# $(error AUTOCONF_H is not defined) +#endif + +#ccflags-y += -imacros $(AUTOCONF_H) + +# Force build fail on modpost warning +KBUILD_MODPOST_FAIL_ON_WARNINGS := y + +############################################################################### +ccflags-y += -Werror +ccflags-y += -Wno-error=format +ccflags-y += -Wno-error=format-extra-args +ccflags-y += -Wframe-larger-than=1024 + +############################################################################### +MODULE_NAME := conninfra +obj-m += $(MODULE_NAME).o + +############################################################################### +# common_main +############################################################################### +ccflags-y += \ + -I$(SUBDIRS)/include \ + -I$(SUBDIRS)/base/include \ + -I$(SUBDIRS)/core/include \ + -I$(SUBDIRS)/conf/include \ + -I$(SUBDIRS)/platform/include + +$(MODULE_NAME)-objs += base/ring.o +$(MODULE_NAME)-objs += base/osal.o +$(MODULE_NAME)-objs += base/msg_thread.o +$(MODULE_NAME)-objs += core/conninfra_core.o +$(MODULE_NAME)-objs += src/conninfra_dev.o +$(MODULE_NAME)-objs += src/conninfra.o +$(MODULE_NAME)-objs += platform/consys_hw.o +$(MODULE_NAME)-objs += platform/consys_hw_plat_data.o +$(MODULE_NAME)-objs += platform/pmic_mng.o +$(MODULE_NAME)-objs += platform/emi_mng.o +$(MODULE_NAME)-objs += platform/consys_reg_mng.o + +# By Plaftfrom +# MT7986 +ifeq ($(CONFIG_MTK_CONNINFRA_APSOC_MT7986),y) +ccflags-y += \ + -I$(SUBDIRS)/platform/mt7986/include -DCONNINFRA_APSOC_MT7986 +$(MODULE_NAME)-objs += platform/mt7986/mt7986.o +$(MODULE_NAME)-objs += platform/mt7986/mt7986_pmic.o +$(MODULE_NAME)-objs += platform/mt7986/mt7986_consys_reg.o +$(MODULE_NAME)-objs += platform/mt7986/mt7986_pos.o +$(MODULE_NAME)-objs += platform/mt7986/mt7986_emi.o +endif + +# MT7981 +ifeq ($(CONFIG_MTK_CONNINFRA_APSOC_MT7981),y) +ccflags-y += \ + -I$(SUBDIRS)/platform/mt7981/include -DCONNINFRA_APSOC_MT7981 +$(MODULE_NAME)-objs += platform/mt7981/mt7981.o +$(MODULE_NAME)-objs += platform/mt7981/mt7981_pmic.o +$(MODULE_NAME)-objs += platform/mt7981/mt7981_consys_reg.o +$(MODULE_NAME)-objs += platform/mt7981/mt7981_pos.o +$(MODULE_NAME)-objs += platform/mt7981/mt7981_emi.o +endif \ No newline at end of file diff --git a/package/mtk/drivers/conninfra/src/NOTICE b/package/mtk/drivers/conninfra/src/NOTICE new file mode 100644 index 0000000000..52c1cace2c --- /dev/null +++ b/package/mtk/drivers/conninfra/src/NOTICE @@ -0,0 +1,202 @@ +The GNU General Public License (GPL) + +Version 2, June 1991 + +Copyright (C) 1989, 1991 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. + +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU +General Public License is intended to guarantee your freedom to share and change free software--to make sure the +software is free for all its users. This General Public License applies to most of the Free Software Foundation's +software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is +covered by the GNU Library General Public License instead.) You can apply it to your programs, too. + +When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make +sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you +receive source code or can get it if you want it, that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + +To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to +surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the +software, or if you modify it. + +For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all +the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them +these terms so they know their rights. + +We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal +permission to copy, distribute and/or modify the software. + +Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty +for this free software. If the software is modified by someone else and passed on, we want its recipients to know that +what they have is not the original, so that any problems introduced by others will not reflect on the original authors' +reputations. + +Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors +of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, +we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. + +The precise terms and conditions for copying, distribution and modification follow. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it +may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or +work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to +say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into +another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is +addressed as "you". + +Activities other than copying, distribution and modification are not covered by this License; they are outside its +scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents +constitute a work based on the Program (independent of having been made by running the Program). Whether that is true +depends on what the Program does. + +1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided +that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of +warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other +recipients of the Program a copy of this License along with the Program. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection +in exchange for a fee. + +2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and +copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of +these conditions: + +a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any +change. + +b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the +Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this +License. + +c) If the modified program normally reads commands interactively when run, you must cause it, when started running for +such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright +notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may +redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if +the Program itself is interactive but does not normally print such an announcement, your work based on the Program is +not required to print an announcement.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the +Program, and can be reasonably considered independent and separate works in themselves, then this License, and its +terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same +sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part +regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; +rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the +Program. + +In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the +Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you also do one of the following: + +a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms +of Sections 1 and 2 above on a medium customarily used for software interchange; or, + +b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than +your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source +code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; +or, + +c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This +alternative is allowed only for noncommercial distribution and only if you received the program in object code or +executable form with such an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for making modifications to it. For an executable work, +complete source code means all the source code for all modules it contains, plus any associated interface definition +files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, +the source code distributed need not include anything that is normally distributed (in either source or binary form) +with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless +that component itself accompanies the executable. + +If distribution of executable or object code is made by offering access to copy from a designated place, then offering +equivalent access to copy the source code from the same place counts as distribution of the source code, even though +third parties are not compelled to copy the source along with the object code. + +4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your +rights under this License. However, parties who have received copies, or rights, from you under this License will not +have their licenses terminated so long as such parties remain in full compliance. + +5. You are not required to accept this License, since you have not signed it. However, nothing else grants you +permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do +not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you +indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or +modifying the Program or works based on it. + +6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a +license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You +may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not +responsible for enforcing compliance by third parties to this License. + +7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to +patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the +conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as +to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence +you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution +of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy +both it and this License would be to refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the +section is intended to apply and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest +validity of any such claims; this section has the sole purpose of protecting the integrity of the free software +distribution system, which is implemented by public license practices. Many people have made generous contributions to +the wide range of software distributed through that system in reliance on consistent application of that system; it is +up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee +cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted +interfaces, the original copyright holder who places the Program under this License may add an explicit geographical +distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. +Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or +concerns. + +Each version is given a distinguishing version number. If the Program specifies a version number of this License which +applies to it and "any later version", you have the option of following the terms and conditions either of that version +or of any later version published by the Free Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software Foundation. + +10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are +different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, +write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two +goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of +software generally. + +NO WARRANTY + +11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM +"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + +12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY +WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, +SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT +LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF +THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY +OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + + + + diff --git a/package/mtk/drivers/conninfra/src/base/include/msg_thread.h b/package/mtk/drivers/conninfra/src/base/include/msg_thread.h new file mode 100644 index 0000000000..6cb462821d --- /dev/null +++ b/package/mtk/drivers/conninfra/src/base/include/msg_thread.h @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _BASE_MSG_THREAD_H_ +#define _BASE_MSG_THREAD_H_ + +#include "osal.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +#define MSG_THREAD_OP_DATA_SIZE 8 +#define MSG_THREAD_OP_BUF_SIZE 64 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +struct msg_op_data { + unsigned int op_id; /* Event ID */ + unsigned int info_bit; /* Reserved */ + size_t op_data[MSG_THREAD_OP_DATA_SIZE]; /* OP Data */ +}; + +struct msg_op { + struct msg_op_data op; + OSAL_SIGNAL signal; + int result; + atomic_t ref_count; +}; + + +struct msg_op_q { + OSAL_SLEEPABLE_LOCK lock; + unsigned int write; + unsigned int read; + unsigned int size; + struct msg_op *queue[MSG_THREAD_OP_BUF_SIZE]; +}; + +typedef OSAL_OP_DAT msg_evt_op; +typedef int(*msg_opid_func) (struct msg_op_data *); + +struct msg_thread_ctx { + OSAL_THREAD thread; /* core thread */ + OSAL_EVENT evt; + + struct msg_op_q free_op_q; /* free op queue */ + struct msg_op_q active_op_q; /* active op queue */ + struct msg_op op_q_inst[MSG_THREAD_OP_BUF_SIZE]; /* real op instances */ + struct msg_op *cur_op; /* current op */ + + int op_func_size; + const msg_opid_func *op_func; + + struct osal_op_history op_history; +}; + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +#define MSG_OP_TIMEOUT 20000 + +int msg_thread_init(struct msg_thread_ctx *ctx, const char *name, + const msg_opid_func *func, int op_size); +int msg_thread_deinit(struct msg_thread_ctx *ctx); + +/* timeout: + * 0: default value (by MSG_OP_TIMEOUT define) + * >0: cutom timeout (ms) + */ +int msg_thread_send(struct msg_thread_ctx *ctx, int opid); +int msg_thread_send_1(struct msg_thread_ctx *ctx, int opid, + size_t param1); +int msg_thread_send_2(struct msg_thread_ctx *ctx, int opid, + size_t param1, size_t param2); + +int msg_thread_send_wait(struct msg_thread_ctx *ctx, int opid, + int timeout); +int msg_thread_send_wait_1(struct msg_thread_ctx *ctx, int opid, + int timeout, size_t param1); +int msg_thread_send_wait_2(struct msg_thread_ctx *ctx, int opid, + int timeout, size_t param1, size_t param2); +int msg_thread_send_wait_3(struct msg_thread_ctx *ctx, int opid, int timeout, size_t param1, + size_t param2,size_t param3); + +int msg_thread_dump(struct msg_thread_ctx *ctx); + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _BASE_MSG_THREAD_H_ */ diff --git a/package/mtk/drivers/conninfra/src/base/include/osal.h b/package/mtk/drivers/conninfra/src/base/include/osal.h new file mode 100644 index 0000000000..2eb2a753ad --- /dev/null +++ b/package/mtk/drivers/conninfra/src/base/include/osal.h @@ -0,0 +1,399 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + + +/*! \file + * \brief Declaration of library functions + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. + */ + +#ifndef _OSAL_H_ +#define _OSAL_H_ + +#include +#include +#include +#include +#include "ring.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define OS_BIT_OPS_SUPPORT 1 + +#ifndef MTK_CONN_BOOL_TRUE +#define MTK_CONN_BOOL_FALSE ((MTK_CONN_BOOL) 0) +#define MTK_CONN_BOOL_TRUE ((MTK_CONN_BOOL) 1) +#endif + +#define _osal_inline_ inline + +#define MAX_THREAD_NAME_LEN 16 +#define MAX_HISTORY_NAME_LEN 16 +#define OSAL_OP_BUF_SIZE 64 + + +#if (defined(CONFIG_MTK_GMO_RAM_OPTIMIZE) && !defined(CONFIG_MTK_ENG_BUILD)) +#define OSAL_OP_DATA_SIZE 8 +#else +#define OSAL_OP_DATA_SIZE 32 +#endif + +#define DBG_LOG_STR_SIZE 256 + +#define osal_sizeof(x) sizeof(x) + +#define osal_array_size(x) ARRAY_SIZE(x) + +#ifndef NAME_MAX +#define NAME_MAX 256 +#endif + +#define WMT_OP_BIT(x) (0x1UL << x) +#define WMT_OP_HIF_BIT WMT_OP_BIT(0) + +#define GET_BIT_MASK(value, mask) ((value) & (mask)) +#define SET_BIT_MASK(pdest, value, mask) (*(pdest) = (GET_BIT_MASK(*(pdest), ~(mask)) | GET_BIT_MASK(value, mask))) +#define GET_BIT_RANGE(data, end, begin) ((data) & GENMASK(end, begin)) +#define SET_BIT_RANGE(pdest, data, end, begin) (SET_BIT_MASK(pdest, data, GENMASK(end, begin))) + +#define RB_LATEST(prb) ((prb)->write - 1) +#define RB_SIZE(prb) ((prb)->size) +#define RB_MASK(prb) (RB_SIZE(prb) - 1) +#define RB_COUNT(prb) ((prb)->write - (prb)->read) +#define RB_FULL(prb) (RB_COUNT(prb) >= RB_SIZE(prb)) +#define RB_EMPTY(prb) ((prb)->write == (prb)->read) + +#define RB_INIT(prb, qsize) \ +do { \ + (prb)->read = (prb)->write = 0; \ + (prb)->size = (qsize); \ +} while (0) + +#define RB_PUT(prb, value) \ +do { \ + if (!RB_FULL(prb)) { \ + (prb)->queue[(prb)->write & RB_MASK(prb)] = value; \ + ++((prb)->write); \ + } \ + else { \ + pr_warn("RB is full!"); \ + } \ +} while (0) + +#define RB_GET(prb, value) \ +do { \ + if (!RB_EMPTY(prb)) { \ + value = (prb)->queue[(prb)->read & RB_MASK(prb)]; \ + ++((prb)->read); \ + if (RB_EMPTY(prb)) { \ + (prb)->read = (prb)->write = 0; \ + } \ + } \ + else { \ + value = NULL; \ + pr_warn("RB is empty!"); \ + } \ +} while (0) + +#define RB_GET_LATEST(prb, value) \ +do { \ + if (!RB_EMPTY(prb)) { \ + value = (prb)->queue[RB_LATEST(prb) & RB_MASK(prb)]; \ + if (RB_EMPTY(prb)) { \ + (prb)->read = (prb)->write = 0; \ + } \ + } \ + else { \ + value = NULL; \ + } \ +} while (0) + + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef int MTK_CONN_BOOL; + +typedef int(*P_COND) (void *); + +typedef struct _OSAL_UNSLEEPABLE_LOCK_ { + spinlock_t lock; + unsigned long flag; +} OSAL_UNSLEEPABLE_LOCK, *P_OSAL_UNSLEEPABLE_LOCK; + +typedef struct _OSAL_SLEEPABLE_LOCK_ { + struct mutex lock; +} OSAL_SLEEPABLE_LOCK, *P_OSAL_SLEEPABLE_LOCK; + +typedef struct _OSAL_SIGNAL_ { + struct completion comp; + unsigned int timeoutValue; + unsigned int timeoutExtension; /* max number of timeout caused by thread not able to acquire CPU */ +} OSAL_SIGNAL, *P_OSAL_SIGNAL; + +typedef struct _OSAL_EVENT_ { + wait_queue_head_t waitQueue; + unsigned int timeoutValue; + int waitFlag; + +} OSAL_EVENT, *P_OSAL_EVENT; + +/* Data collected from sched_entity and sched_statistics */ +typedef struct _OSAL_THREAD_SCHEDSTATS_ { + unsigned long long time; /* when marked: the profiling start time(ms), when unmarked: total duration(ms) */ + unsigned long long exec; /* time spent in exec (sum_exec_runtime) */ + unsigned long long runnable; /* time spent in run-queue while not being scheduled (wait_sum) */ + unsigned long long iowait; /* time spent waiting for I/O (iowait_sum) */ +} OSAL_THREAD_SCHEDSTATS, *P_OSAL_THREAD_SCHEDSTATS; + +typedef struct _OSAL_THREAD_ { + struct task_struct *pThread; + void *pThreadFunc; + void *pThreadData; + char threadName[MAX_THREAD_NAME_LEN]; +} OSAL_THREAD, *P_OSAL_THREAD; + + +typedef struct _OSAL_FIFO_ { + /*fifo definition */ + void *pFifoBody; + spinlock_t fifoSpinlock; + /*fifo operations */ + int (*FifoInit)(struct _OSAL_FIFO_ *pFifo, unsigned char *buf, unsigned int); + int (*FifoDeInit)(struct _OSAL_FIFO_ *pFifo); + int (*FifoReset)(struct _OSAL_FIFO_ *pFifo); + int (*FifoSz)(struct _OSAL_FIFO_ *pFifo); + int (*FifoAvailSz)(struct _OSAL_FIFO_ *pFifo); + int (*FifoLen)(struct _OSAL_FIFO_ *pFifo); + int (*FifoIsEmpty)(struct _OSAL_FIFO_ *pFifo); + int (*FifoIsFull)(struct _OSAL_FIFO_ *pFifo); + int (*FifoDataIn)(struct _OSAL_FIFO_ *pFifo, const void *buf, unsigned int len); + int (*FifoDataOut)(struct _OSAL_FIFO_ *pFifo, void *buf, unsigned int len); +} OSAL_FIFO, *P_OSAL_FIFO; + +typedef struct firmware osal_firmware; + +typedef struct _OSAL_OP_DAT { + unsigned int opId; /* Event ID */ + unsigned int u4InfoBit; /* Reserved */ + size_t au4OpData[OSAL_OP_DATA_SIZE]; /* OP Data */ +} OSAL_OP_DAT, *P_OSAL_OP_DAT; + +typedef struct _OSAL_LXOP_ { + OSAL_OP_DAT op; + OSAL_SIGNAL signal; + int result; + atomic_t ref_count; +} OSAL_OP, *P_OSAL_OP; + +typedef struct _OSAL_LXOP_Q { + OSAL_SLEEPABLE_LOCK sLock; + unsigned int write; + unsigned int read; + unsigned int size; + P_OSAL_OP queue[OSAL_OP_BUF_SIZE]; +} OSAL_OP_Q, *P_OSAL_OP_Q; + +typedef struct _OSAL_BIT_OP_VAR_ { + unsigned long data; + OSAL_UNSLEEPABLE_LOCK opLock; +} OSAL_BIT_OP_VAR, *P_OSAL_BIT_OP_VAR; + +typedef unsigned int (*P_OSAL_EVENT_CHECKER) (P_OSAL_THREAD pThread); + +struct osal_op_history_entry { + void *opbuf_address; + unsigned int op_id; + unsigned int opbuf_ref_count; + unsigned int op_info_bit; + size_t param_0; + size_t param_1; + size_t param_2; + size_t param_3; + unsigned long long ts; + unsigned long usec; +}; + +struct osal_op_history { + struct ring ring_buffer; + struct osal_op_history_entry *queue; + spinlock_t lock; + struct ring dump_ring_buffer; + struct work_struct dump_work; + unsigned char name[MAX_HISTORY_NAME_LEN]; +}; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +void FlashRead(char *name,unsigned char *value, unsigned long offset, unsigned long size); +void FlashWrite(char *name, unsigned char *p, unsigned long a, unsigned long b); + +unsigned int osal_strlen(const char *str); +int osal_strcmp(const char *dst, const char *src); +int osal_strncmp(const char *dst, const char *src, unsigned int len); +char *osal_strcpy(char *dst, const char *src); +char *osal_strncpy(char *dst, const char *src, unsigned int len); +char *osal_strcat(char *dst, const char *src); +char *osal_strncat(char *dst, const char *src, unsigned int len); +char *osal_strchr(const char *str, unsigned char c); +char *osal_strsep(char **str, const char *c); +int osal_strtol(const char *str, unsigned int adecimal, long *res); +char *osal_strstr(char *str1, const char *str2); +char *osal_strnstr(char *str1, const char *str2, int n); + +void osal_bug_on(unsigned int val); + +int osal_snprintf(char *buf, unsigned int len, const char *fmt, ...); + +int osal_sprintf(char *str, const char *format, ...); +void *osal_malloc(unsigned int size); +void osal_free(const void *dst); +void *osal_memset(void *buf, int i, unsigned int len); +void *osal_memcpy(void *dst, const void *src, unsigned int len); +void osal_memcpy_fromio(void *dst, const void *src, unsigned int len); +void osal_memcpy_toio(void *dst, const void *src, unsigned int len); +int osal_memcmp(const void *buf1, const void *buf2, unsigned int len); + +int osal_sleep_ms(unsigned int ms); +int osal_udelay(unsigned int us); +int osal_usleep_range(unsigned long min, unsigned long max); + +int osal_fifo_init(P_OSAL_FIFO pFifo, unsigned char *buffer, unsigned int size); +void osal_fifo_deinit(P_OSAL_FIFO pFifo); +int osal_fifo_reset(P_OSAL_FIFO pFifo); +unsigned int osal_fifo_in(P_OSAL_FIFO pFifo, unsigned char *buffer, + unsigned int size); +unsigned int osal_fifo_out(P_OSAL_FIFO pFifo, unsigned char *buffer, + unsigned int size); +unsigned int osal_fifo_len(P_OSAL_FIFO pFifo); +unsigned int osal_fifo_sz(P_OSAL_FIFO pFifo); +unsigned int osal_fifo_avail(P_OSAL_FIFO pFifo); +unsigned int osal_fifo_is_empty(P_OSAL_FIFO pFifo); +unsigned int osal_fifo_is_full(P_OSAL_FIFO pFifo); + +#if defined(CONFIG_PROVE_LOCKING) +#define osal_unsleepable_lock_init(l) { spin_lock_init(&((l)->lock)); } +#else +int osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK); +#endif +int osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK); +int osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK); +int osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK); + +#if defined(CONFIG_PROVE_LOCKING) +#define osal_sleepable_lock_init(l) { mutex_init(&((l)->lock)); } +#else +int osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK); +#endif +int osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); +int osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); +int osal_trylock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK); +int osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK); + +int osal_signal_init(P_OSAL_SIGNAL); +int osal_wait_for_signal(P_OSAL_SIGNAL); +int osal_wait_for_signal_timeout(P_OSAL_SIGNAL, P_OSAL_THREAD); +int osal_raise_signal(P_OSAL_SIGNAL); +int osal_signal_active_state(P_OSAL_SIGNAL pSignal); +int osal_signal_deinit(P_OSAL_SIGNAL); + +int osal_event_init(P_OSAL_EVENT); +int osal_wait_for_event(P_OSAL_EVENT, P_COND, void*); +int osal_wait_for_event_timeout(P_OSAL_EVENT, P_COND, void*); +extern int osal_trigger_event(P_OSAL_EVENT); + +int osal_event_deinit(P_OSAL_EVENT); +long osal_wait_for_event_bit_set(P_OSAL_EVENT pEvent, unsigned long *pState, unsigned int bitOffset); +long osal_wait_for_event_bit_clr(P_OSAL_EVENT pEvent, unsigned long *pState, unsigned int bitOffset); + +int osal_thread_create(P_OSAL_THREAD); +int osal_thread_run(P_OSAL_THREAD); +int osal_thread_should_stop(P_OSAL_THREAD); +int osal_thread_stop(P_OSAL_THREAD); +/*int osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT);*/ +int osal_thread_wait_for_event(P_OSAL_THREAD, P_OSAL_EVENT, P_OSAL_EVENT_CHECKER); +/*check pOsalLxOp and OSAL_THREAD_SHOULD_STOP*/ +int osal_thread_destroy(P_OSAL_THREAD); +int osal_thread_sched_mark(P_OSAL_THREAD, P_OSAL_THREAD_SCHEDSTATS schedstats); +int osal_thread_sched_unmark(P_OSAL_THREAD pThread, P_OSAL_THREAD_SCHEDSTATS schedstats); + +int osal_clear_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData); +int osal_set_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData); +int osal_test_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData); +int osal_test_and_clear_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData); +int osal_test_and_set_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData); + +int osal_gettimeofday(int *sec, int *usec); +int osal_gettimeofday2(struct timeval *tv); + +//int osal_printtimeofday(const unsigned char *prefix); +void osal_get_local_time(unsigned long long *sec, unsigned long *nsec); +unsigned long long osal_elapsed_us(unsigned long long ts, unsigned long usec); + +void osal_buffer_dump(const unsigned char *buf, const unsigned char *title, unsigned int len, unsigned int limit); +void osal_buffer_dump_data(const unsigned int *buf, const unsigned char *title, const unsigned int len, const unsigned int limit, + const int flag); + +unsigned int osal_op_get_id(P_OSAL_OP pOp); +MTK_CONN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp); +void osal_op_raise_signal(P_OSAL_OP pOp, int result); +void osal_set_op_result(P_OSAL_OP pOp, int result); +void osal_opq_dump(const char *qName, P_OSAL_OP_Q pOpQ); +void osal_opq_dump_locked(const char *qName, P_OSAL_OP_Q pOpQ); +MTK_CONN_BOOL osal_opq_has_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp); + +int osal_ftrace_print(const char *str, ...); +int osal_ftrace_print_ctrl(int flag); + +void osal_dump_thread_state(const unsigned char *name); +void osal_op_history_init(struct osal_op_history *log_history, int queue_size); +void osal_op_history_save(struct osal_op_history *log_history, P_OSAL_OP pOp); +void osal_op_history_print(struct osal_op_history *log_history, char *name); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _OSAL_H_ */ diff --git a/package/mtk/drivers/conninfra/src/base/include/ring.h b/package/mtk/drivers/conninfra/src/base/include/ring.h new file mode 100644 index 0000000000..81168ce866 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/base/include/ring.h @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +#ifndef _RING_H_ +#define _RING_H_ + +struct ring { + /* addr where ring buffer starts */ + void *base; + /* addr storing the next writable pos, guaranteed to be >= read except when write overflow, but it's ok. */ + unsigned int write; + /* addr storing the next readable pos, except when read == write as buffer empty */ + unsigned int read; + /* must be power of 2 */ + unsigned int max_size; +}; + +struct ring_segment { + /* addr points into ring buffer for read/write */ + void *ring_pt; + /* size to read/write */ + unsigned int sz; + /* pos in external data buffer to read/write */ + unsigned int data_pos; + /* the size to be read/write after this segment completed */ + unsigned int remain; +}; + +void ring_init(void *base, unsigned int max_size, unsigned int read, + unsigned int write, struct ring *ring); +unsigned int ring_read_prepare(unsigned int sz, struct ring_segment *seg, struct ring *ring); +#define ring_read_all_prepare(seg, ring) ring_read_prepare((ring)->max_size, seg, ring) +unsigned int ring_write_prepare(unsigned int sz, struct ring_segment *seg, struct ring *ring); +unsigned int ring_overwrite_prepare(unsigned int sz, + struct ring_segment *seg, struct ring *ring); + +/* making sure max_size is power of 2 */ +#define RING_VALIDATE_SIZE(max_size) WARN_ON(!max_size || (max_size & (max_size - 1))) + +#define RING_EMPTY(ring) ((ring)->read == (ring)->write) +/* equation works even when write overflow */ +#define RING_SIZE(ring) ((ring)->write - (ring)->read) +#define RING_FULL(ring) (RING_SIZE(ring) == (ring)->max_size) +#define RING_WRITE_REMAIN_SIZE(ring) ((ring)->max_size - RING_SIZE(ring)) + +#define RING_READ_FOR_EACH(_sz, _seg, _ring) \ + for (ring_read_prepare(_sz, &(_seg), _ring), \ + _ring_segment_prepare((_ring)->read, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_read_commit(&(_seg), (_ring)), _ring_segment_prepare((_ring)->read, \ + &(_seg), (_ring))) + +#define RING_READ_ALL_FOR_EACH(seg, ring) RING_READ_FOR_EACH((ring)->max_size, seg, ring) + +#define RING_READ_FOR_EACH_ITEM(_sz, _seg, _ring) \ + for (ring_read_prepare(_sz, &(_seg), _ring), \ + _ring_segment_prepare_item((_ring)->read, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_read_commit(&(_seg), (_ring)), _ring_segment_prepare_item((_ring)->read, \ + &(_seg), (_ring))) + +#define RING_WRITE_FOR_EACH(_sz, _seg, _ring) \ + for (ring_write_prepare(_sz, &(_seg), _ring),\ + _ring_segment_prepare((_ring)->write, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_write_commit(&(_seg), (_ring)), _ring_segment_prepare((_ring)->write, \ + &(_seg), (_ring))) + +#define RING_OVERWRITE_FOR_EACH(_sz, _seg, _ring) \ + for (ring_overwrite_prepare(_sz, &(_seg), _ring), \ + _ring_segment_prepare((_ring)->write, &(_seg), (_ring)); \ + (_seg).sz > 0; \ + _ring_write_commit(&(_seg), (_ring)), _ring_segment_prepare((_ring)->write, \ + &(_seg), (_ring))) + +void ring_dump(const char *title, struct ring *ring); +void ring_dump_segment(const char *title, struct ring_segment *seg); + + +/* ring Buffer Internal API */ +void _ring_segment_prepare(unsigned int from, struct ring_segment *seg, struct ring *ring); +void _ring_segment_prepare_item(unsigned int from, struct ring_segment *seg, struct ring *ring); +void _ring_read_commit(struct ring_segment *seg, struct ring *ring); +void _ring_write_commit(struct ring_segment *seg, struct ring *ring); + +#endif diff --git a/package/mtk/drivers/conninfra/src/base/msg_thread.c b/package/mtk/drivers/conninfra/src/base/msg_thread.c new file mode 100644 index 0000000000..4a9c0cba4a --- /dev/null +++ b/package/mtk/drivers/conninfra/src/base/msg_thread.c @@ -0,0 +1,716 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ +#include +#include "msg_thread.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static void msg_opq_dump(const char *qName, struct msg_op_q *op_q); +static void _msg_opq_dump(const char *qName, struct msg_op_q *op_q); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#define MSG_OP_SIZE(prb) ((prb)->size) +#define MSG_OP_MASK(prb) (MSG_OP_SIZE(prb) - 1) +#define MSG_OP_COUNT(prb) ((prb)->write - (prb)->read) +#define MSG_OP_FULL(prb) (MSG_OP_COUNT(prb) >= MSG_OP_SIZE(prb)) +#define MSG_OP_EMPTY(prb) ((prb)->write == (prb)->read) + +#define MSG_OP_INIT(prb, qsize) \ +do { \ + (prb)->read = (prb)->write = 0; \ + (prb)->size = (qsize); \ +} while (0) + +#define MSG_OP_PUT(prb, value) \ +do { \ + if (!MSG_OP_FULL(prb)) { \ + (prb)->queue[(prb)->write & MSG_OP_MASK(prb)] = value; \ + ++((prb)->write); \ + } \ + else { \ + pr_warn("Message queue is full.\n"); \ + } \ +} while (0) + +#define MSG_OP_GET(prb, value) \ +do { \ + if (!MSG_OP_EMPTY(prb)) { \ + value = (prb)->queue[(prb)->read & MSG_OP_MASK(prb)]; \ + ++((prb)->read); \ + if (MSG_OP_EMPTY(prb)) { \ + (prb)->read = (prb)->write = 0; \ + } \ + } \ + else { \ + value = NULL; \ + pr_warn("Message queue is empty.\n"); \ + } \ +} while (0) + + + +#if defined(CONFIG_MTK_ENG_BUILD) || defined(CONFIG_MT_ENG_BUILD) +static bool msg_evt_opq_has_op(struct msg_op_q *op_q, struct msg_op *op) +{ + unsigned int rd; + unsigned int wt; + struct msg_op *tmp_op; + + rd = op_q->read; + wt = op_q->write; + + while (rd != wt) { + tmp_op = op_q->queue[rd & MSG_OP_MASK(op_q)]; + if (op == tmp_op) + return true; + rd++; + } + return false; +} +#endif + +/* + * Utility functions + */ +static int msg_evt_put_op_to_q(struct msg_op_q *op_q, struct msg_op *op) +{ + int ret; + + if (!op_q || !op) { + pr_err("invalid input param: pOpQ(0x%p), pLxOp(0x%p)\n", op_q, op); + return -1; + } + + ret = osal_lock_sleepable_lock(&op_q->lock); + if (ret) { + pr_warn("osal_lock_sleepable_lock iRet(%d)\n", ret); + return -2; + } + +#if defined(CONFIG_MTK_ENG_BUILD) || defined(CONFIG_MT_ENG_BUILD) + if (msg_evt_opq_has_op(op_q, op)) { + pr_err("Op(%p) already exists in queue(%p)\n", op, op_q); + ret = -3; + } +#endif + + /* acquire lock success */ + if (!MSG_OP_FULL(op_q)) + MSG_OP_PUT(op_q, op); + else { + pr_warn("MSG_OP_FULL(%p -> %p)\n", op, op_q); + ret = -4; + } + + osal_unlock_sleepable_lock(&op_q->lock); + + if (ret) { + //osal_opq_dump("FreeOpQ", &g_conninfra_ctx.rFreeOpQ); + //osal_opq_dump("ActiveOpQ", &g_conninfra_ctx.rActiveOpQ); + return ret; + } + return 0; +} + + +/* + * Utility functions + */ +static struct msg_op *msg_evt_get_op_from_q(struct msg_op_q *op_q) +{ + struct msg_op *op; + int ret; + + if (op_q == NULL) { + pr_err("pOpQ = NULL\n"); + return NULL; + } + + ret = osal_lock_sleepable_lock(&op_q->lock); + if (ret) { + pr_err("osal_lock_sleepable_lock iRet(%d)\n", ret); + return NULL; + } + + /* acquire lock success */ + MSG_OP_GET(op_q, op); + osal_unlock_sleepable_lock(&op_q->lock); + + if (op == NULL) { + pr_warn("MSG_OP_GET(%p) return NULL\n", op_q); + //osal_opq_dump("FreeOpQ", &g_conninfra_ctx.rFreeOpQ); + //osal_opq_dump("ActiveOpQ", &g_conninfra_ctx.rActiveOpQ); + } + + return op; +} + +static void _msg_opq_dump(const char *qName, struct msg_op_q *op_q) +{ + /* Line format: + * [LogicalIdx(PhysicalIdx)]Address:OpId(Ref)(Result)-Info-OpData0,OpData1,OpData2,OpData3,OpData5_ + * [LogicalIdx] max 10+2=12 chars (decimal) + * (PhysicalIdx) max 10+2=12 chars (decimal) + * Address: max 16+1=17 chars (hex) + * OpId max 10 chars (decimal) + * (Ref) max 2+2=4 chars (should only be 1 digit, reserve 2 in case of negative number) + * (Result) max 11+2=13 chars (signed decimal) + * -Info- max 8+2=10 chars (hex) + * OpData, max 16+1=17 chars (hex) + */ +#define OPQ_DUMP_OP_PER_LINE 1 +#define OPQ_DUMP_OPDATA_PER_OP 6 +#define OPQ_DUMP_OP_BUF_SIZE (12 + 12 + 17 + 10 + 4 + 13 + 10 + (17 * (OPQ_DUMP_OPDATA_PER_OP)) + 1) +#define OPQ_DUMP_LINE_BUF_SIZE ((OPQ_DUMP_OP_BUF_SIZE * OPQ_DUMP_OP_PER_LINE) + 1) + unsigned int rd; + unsigned int wt; + unsigned int idx = 0; + unsigned int op_data_idx; + unsigned int buf_idx; + int printed; + struct msg_op *op; + char buf[OPQ_DUMP_LINE_BUF_SIZE]; + + rd = op_q->read; + wt = op_q->write; + + pr_info("%s(%p), sz:%u/%u, rd:%u, wt:%u\n", + qName, op_q, RB_COUNT(op_q), RB_SIZE(op_q), rd, wt); + while (rd != wt && idx < RB_SIZE(op_q)) { + buf_idx = idx % OPQ_DUMP_OP_PER_LINE; + op = op_q->queue[rd & RB_MASK(op_q)]; + + if (buf_idx == 0) { + printed = 0; + buf[0] = 0; + } + + if (op) { + printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed, + "[%u(%u)]%p:%u(%d)(%d)-%u-", + idx, + (rd & RB_MASK(op_q)), + op, + op->op.op_id, + atomic_read(&op->ref_count), + op->result, + op->op.info_bit); + for (op_data_idx = 0; op_data_idx < OPQ_DUMP_OPDATA_PER_OP; op_data_idx++) + printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed, + "%zx,", op->op.op_data[op_data_idx]); + buf[printed-1] = ' '; + } else { + printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed, + "[%u(%u)]%p ", idx, (rd & RB_MASK(op_q)), op); + } + buf[printed++] = ' '; + + if (buf_idx == OPQ_DUMP_OP_PER_LINE - 1 || rd == wt - 1) { + buf[printed - 1] = 0; + pr_info("%s\n", buf); + } + rd++; + idx++; + } +} + +void msg_opq_dump(const char *qName, struct msg_op_q *op_q) +{ + int err; + + err = osal_lock_sleepable_lock(&op_q->lock); + if (err) { + pr_info("Failed to lock queue (%d)\n", err); + return; + } + + _msg_opq_dump(qName, op_q); + + osal_unlock_sleepable_lock(&op_q->lock); +} + +/* + * msg_evt_thread API + */ + +int msg_evt_put_op_to_free_queue(struct msg_thread_ctx *ctx, struct msg_op *op) +{ + if (msg_evt_put_op_to_q(&ctx->free_op_q, op)) + return -1; + return 0; +} + + +struct msg_op *msg_evt_get_free_op(struct msg_thread_ctx *ctx) +{ + struct msg_op *op = NULL; + + if (ctx == NULL) { + pr_warn("ctx is null.\n"); + return op; + } + op = msg_evt_get_op_from_q(&ctx->free_op_q); + if (op) + osal_memset(op, 0, osal_sizeof(struct msg_op)); + return op; +} + +int msg_evt_put_op_to_active(struct msg_thread_ctx *ctx, struct msg_op *op) +{ + P_OSAL_SIGNAL signal = NULL; + int wait_ret = -1; + int ret = 0; + + do { + if (!ctx || !op) { + pr_err("msg_thread_ctx(0x%p), op(0x%p)\n", ctx, op); + break; + } + + signal = &op->signal; + if (signal->timeoutValue) { + op->result = -9; + osal_signal_init(signal); + atomic_set(&op->ref_count, 1); + } else + atomic_set(&op->ref_count, 0); + + /* Increment ref_count by 1 as wmtd thread will hold a reference also, + * this must be done here instead of on target thread, because + * target thread might not be scheduled until a much later time, + * allowing current thread to decrement ref_count at the end of function, + * putting op back to free queue before target thread has a chance to process. + */ + atomic_inc(&op->ref_count); + + /* put to active Q */ + ret = msg_evt_put_op_to_q(&ctx->active_op_q, op); + if (ret) { + pr_warn("put to active queue fail\n"); + atomic_dec(&op->ref_count); + break; + } + + /* wake up conninfra_cored */ + osal_trigger_event(&ctx->evt); + + if (signal->timeoutValue == 0) { + //ret = -1; + /* Not set timeout, don't wait */ + /* pr_info("[%s] timeout is zero", __func__);*/ + break; + } + + /* check result */ + wait_ret = osal_wait_for_signal_timeout(signal, &ctx->thread); + /*pr_info("osal_wait_for_signal_timeout:%d result=[%d]\n", + wait_ret, op->result);*/ + + if (wait_ret == 0) + pr_warn("opId(%d) completion timeout\n", op->op.op_id); + else if (op->result) + pr_info("opId(%d) result:%d\n", + op->op.op_id, op->result); + + /* op completes, check result */ + ret = op->result; + } while (0); + + if (op != NULL && signal != NULL && signal->timeoutValue && + atomic_dec_and_test(&op->ref_count)) { + /* put Op back to freeQ */ + msg_evt_put_op_to_free_queue(ctx, op); + } + + return ret; +} + + +int msg_thread_send(struct msg_thread_ctx *ctx, int opid) +{ + return msg_thread_send_2(ctx, opid, 0, 0); +} + +int msg_thread_send_1(struct msg_thread_ctx *ctx, int opid, + size_t param1) +{ + return msg_thread_send_2(ctx, opid, param1, 0); +} + +int msg_thread_send_2(struct msg_thread_ctx *ctx, int opid, + size_t param1, size_t param2) +{ + struct msg_op *op = NULL; + P_OSAL_SIGNAL signal; + int ret; + + op = msg_evt_get_free_op(ctx); + if (!op) { + pr_err("[%s] can't get free op\n", __func__); + return -1; + } + op->op.op_id = opid; + op->op.op_data[0] = param1; + op->op.op_data[1] = param2; + + signal = &op->signal; + //signal->timeoutValue = timeout > 0 ? timeout : MSG_OP_TIMEOUT; + signal->timeoutValue = 0; + ret = msg_evt_put_op_to_active(ctx, op); + + return ret; +} + +int msg_thread_send_wait(struct msg_thread_ctx *ctx, int opid, + int timeout) +{ + return msg_thread_send_wait_3(ctx, opid, timeout, 0, 0, 0); +} + +int msg_thread_send_wait_1(struct msg_thread_ctx *ctx, + int opid, int timeout, + size_t param1) +{ + return msg_thread_send_wait_3(ctx, opid, timeout, param1, 0, 0); +} + + +int msg_thread_send_wait_2(struct msg_thread_ctx *ctx, + int opid, int timeout, + size_t param1, + size_t param2) +{ + return msg_thread_send_wait_3(ctx, opid, timeout, param1, param2, 0); +} + +int msg_thread_send_wait_3(struct msg_thread_ctx *ctx, + int opid, int timeout, + size_t param1, + size_t param2, + size_t param3) +{ + struct msg_op *op = NULL; + P_OSAL_SIGNAL signal; + int ret; + + op = msg_evt_get_free_op(ctx); + if (!op) { + pr_err("can't get free op for 0x%x\n", opid); + return -1; + } + op->op.op_id = opid; + op->op.op_data[0] = param1; + op->op.op_data[1] = param2; + op->op.op_data[2] = param3; + + signal = &op->signal; + signal->timeoutValue = timeout > 0 ? timeout : MSG_OP_TIMEOUT; + ret = msg_evt_put_op_to_active(ctx, op); + return ret; + +} + +void msg_op_history_save(struct osal_op_history *log_history, struct msg_op *op) +{ + struct osal_op_history_entry *entry = NULL; + struct ring_segment seg; + int index; + unsigned long long sec = 0; + unsigned long usec = 0; + unsigned long flags; + + if (log_history->queue == NULL) + return; + + osal_get_local_time(&sec, &usec); + + spin_lock_irqsave(&(log_history->lock), flags); + RING_OVERWRITE_FOR_EACH(1, seg, &log_history->ring_buffer) { + index = seg.ring_pt - log_history->ring_buffer.base; + entry = &log_history->queue[index]; + } + + if (entry == NULL) { + pr_info("Entry is null, size %d\n", + RING_SIZE(&log_history->ring_buffer)); + spin_unlock_irqrestore(&(log_history->lock), flags); + return; + } + + entry->opbuf_address = op; + entry->op_id = op->op.op_id; + entry->opbuf_ref_count = atomic_read(&op->ref_count); + entry->op_info_bit = op->op.info_bit; + entry->param_0 = op->op.op_data[0]; + entry->param_1 = op->op.op_data[1]; + entry->param_2 = op->op.op_data[2]; + entry->param_3 = op->op.op_data[3]; + entry->ts = sec; + entry->usec = usec; + spin_unlock_irqrestore(&(log_history->lock), flags); +} + +unsigned int msg_evt_wait_event_checker(P_OSAL_THREAD thread) +{ + struct msg_thread_ctx *ctx = NULL; + + if (thread) { + ctx = (struct msg_thread_ctx *) (thread->pThreadData); + return !MSG_OP_EMPTY(&ctx->active_op_q); + } + return 0; +} + +int msg_evt_set_current_op(struct msg_thread_ctx *ctx, struct msg_op *op) +{ + ctx->cur_op = op; + return 0; +} + +int msg_evt_opid_handler(struct msg_thread_ctx *ctx, struct msg_op_data *op) +{ + int opid, ret; + + /*sanity check */ + if (op == NULL) { + pr_warn("null op\n"); + return -1; + } + if (ctx == NULL) { + pr_warn("null evt thread ctx\n"); + return -2; + } + + opid = op->op_id; + + if (opid >= ctx->op_func_size) { + pr_err("msg_evt_thread invalid OPID(%d)\n", opid); + return -3; + } + + if (ctx->op_func[opid] == NULL) { + pr_err("null handler (%d)\n", opid); + return -4; + } + ret = (*(ctx->op_func[opid])) (op); + return ret; +} + +static int msg_evt_thread(void *pvData) +{ + struct msg_thread_ctx *ctx = (struct msg_thread_ctx *)pvData; + P_OSAL_EVENT evt = NULL; + struct msg_op *op; + int ret; + + if (ctx == NULL) { + pr_err("msg_evt_thread (NULL)\n"); + return -1; + } + + evt = &(ctx->evt); + + for (;;) { + op = NULL; + evt->timeoutValue = 0; + + osal_thread_wait_for_event(&ctx->thread, evt, msg_evt_wait_event_checker); + + if (osal_thread_should_stop(&ctx->thread)) { + pr_info("msg_evt_thread thread should stop now...\n"); + /* TODO: clean up active opQ */ + break; + } + /* get Op from activeQ */ + op = msg_evt_get_op_from_q(&ctx->active_op_q); + if (!op) { + pr_warn("get op from activeQ fail\n"); + continue; + } + + /* TODO: save op history */ + msg_op_history_save(&ctx->op_history, op); + msg_evt_set_current_op(ctx, op); + ret = msg_evt_opid_handler(ctx, &op->op); + msg_evt_set_current_op(ctx, NULL); + + if (ret) + pr_warn("opid (0x%x) failed, ret(%d)\n", + op->op.op_id, ret); + + if (atomic_dec_and_test(&op->ref_count)) { + /* msg_evt_free_op(ctx) */ + msg_evt_put_op_to_free_queue(ctx, op); + } else if (op->signal.timeoutValue) { + op->result = ret; + osal_raise_signal(&op->signal); + } + } + + pr_debug("msg evt thread exists\n"); + return 0; +} + +int msg_thread_dump(struct msg_thread_ctx *ctx) +{ + P_OSAL_THREAD p_thread; + struct msg_op *cur_op; + + if (ctx == NULL) { + pr_err("get NULL input\n"); + return 0; + } + p_thread = &ctx->thread; + pr_info("Dump msg_thread_ctx: %s\n", p_thread->threadName); + cur_op = ctx->cur_op; + if (cur_op) { + pr_info("cur_op: %x(%x)-%zx,%zx,%zx,%zx\n", + cur_op->op.op_id, cur_op->op.info_bit, + cur_op->op.op_data[0], cur_op->op.op_data[1], + cur_op->op.op_data[2], cur_op->op.op_data[3]); + } + osal_dump_thread_state(p_thread->threadName); + osal_op_history_print(&(ctx->op_history), p_thread->threadName); + msg_opq_dump("ActiveOpQ", &ctx->active_op_q); + + return 0; +} + +int msg_thread_init(struct msg_thread_ctx *ctx, + const char *thread_name, const msg_opid_func *funcs, + int op_size) +{ + int r = 0, i; + P_OSAL_THREAD p_thread; + + osal_memset(ctx, 0, sizeof(struct msg_thread_ctx)); + + ctx->op_func = funcs; + ctx->op_func_size = op_size; + + /* init thread inst */ + p_thread = &ctx->thread; + + osal_strncpy(p_thread->threadName, thread_name, + sizeof(p_thread->threadName)); + + p_thread->pThreadData = (void *) ctx; + p_thread->pThreadFunc = (void *) msg_evt_thread; + r = osal_thread_create(p_thread); + + if (r) { + pr_err("osal_thread_create(0x%p) fail(%d)\n", p_thread, r); + return -1; + } + + osal_event_init(&ctx->evt); + osal_sleepable_lock_init(&ctx->active_op_q.lock); + osal_sleepable_lock_init(&ctx->free_op_q.lock); + + /* Initialize op queue */ + MSG_OP_INIT(&ctx->free_op_q, MSG_THREAD_OP_BUF_SIZE); + MSG_OP_INIT(&ctx->active_op_q, MSG_THREAD_OP_BUF_SIZE); + + /* Put all to free Q */ + for (i = 0; i < MSG_THREAD_OP_BUF_SIZE; i++) { + osal_signal_init(&(ctx->op_q_inst[i].signal)); + msg_evt_put_op_to_free_queue(ctx, &(ctx->op_q_inst[i])); + } + + osal_op_history_init(&ctx->op_history, 16); + + r = osal_thread_run(p_thread); + if (r) { + pr_err("osal_thread_run(evt_thread 0x%p) fail(%d)\n", + p_thread, r); + return -2; + } + return r; +} + +int msg_thread_deinit(struct msg_thread_ctx *ctx) +{ + int r, i; + P_OSAL_THREAD p_thraed = &ctx->thread; + + r = osal_thread_stop(p_thraed); + if (r) { + pr_err("osal_thread_stop(0x%p) fail(%d)\n", p_thraed, r); + return -1; + } + + for (i = 0; i < MSG_THREAD_OP_BUF_SIZE; i++) + osal_signal_deinit(&(ctx->op_q_inst[i].signal)); + + osal_sleepable_lock_deinit(&ctx->free_op_q.lock); + osal_sleepable_lock_deinit(&ctx->active_op_q.lock); + + r = osal_thread_destroy(p_thraed); + if (r) { + pr_err("osal_thread_stop(0x%p) fail(%d)\n", p_thraed, r); + return -2; + } + + osal_memset(ctx, 0, sizeof(struct msg_thread_ctx)); + + pr_debug("[%s] DONE\n", __func__); + return 0; +} diff --git a/package/mtk/drivers/conninfra/src/base/osal.c b/package/mtk/drivers/conninfra/src/base/osal.c new file mode 100644 index 0000000000..3cdacfd601 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/base/osal.c @@ -0,0 +1,1595 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file + * \brief Declaration of library functions + * Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. + */ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_MTD +#include +#include +#include +#include +#endif /* CONFIG_MTD */ +#include "osal.h" + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +#define TO_STR(_x) #_x +#define BIN_TO_STR(_x) TO_STR(_x) +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +int ftrace_flag = 1; +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + + +int get_default_bin_image_file(char *path) +{ + if(osal_strlen(BIN_TO_STR(EEPROM_NAME))) + osal_sprintf(path, "/lib/firmware/%s", BIN_TO_STR(EEPROM_NAME)); + else + osal_sprintf(path, "/lib/firmware/e2p"); + + pr_info("Use default BIN from:%s.\n", path); + + return 0; +} + +void FlashRead(char *name, unsigned char *value, unsigned long offset, unsigned long size) +{ +#ifdef CONFIG_MTD + int ret; + size_t rdlen; + struct mtd_info *mtd; + + mtd = get_mtd_device_nm(name); + if (IS_ERR(mtd)) { + pr_err("Can't get mtd device!\n"); + return; + } else { + ret = mtd_read(mtd, offset, size, &rdlen, value); + if (rdlen != size) { + pr_err("mtd_read: rdlen is not equal to size!\n"); + } + put_mtd_device(mtd); + } +#endif /* CONFIG_WIFI_MTD */ +} + +void FlashWrite(char *name, unsigned char *p, unsigned long a, unsigned long b) +{ + return; +} + +/*string operations*/ +unsigned int osal_strlen(const char *str) +{ + return strlen(str); +} + +int osal_strcmp(const char *dst, const char *src) +{ + return strcmp(dst, src); +} + +int osal_strncmp(const char *dst, const char *src, unsigned int len) +{ + return strncmp(dst, src, len); +} + +char *osal_strcpy(char *dst, const char *src) +{ + return strncpy(dst, src, strlen(src)+1); +} + +char *osal_strncpy(char *dst, const char *src, unsigned int len) +{ + return strncpy(dst, src, len); +} + +char *osal_strcat(char *dst, const char *src) +{ + return strncat(dst, src, strlen(src)); +} + +char *osal_strncat(char *dst, const char *src, unsigned int len) +{ + return strncat(dst, src, len); +} + +char *osal_strchr(const char *str, unsigned char c) +{ + return strchr(str, c); +} + +char *osal_strsep(char **str, const char *c) +{ + return strsep(str, c); +} + +int osal_strtol(const char *str, unsigned int adecimal, long *res) +{ + if (sizeof(long) == 4) + return kstrtou32(str, adecimal, (unsigned int *) res); + else + return kstrtol(str, adecimal, res); +} + +char *osal_strstr(char *str1, const char *str2) +{ + return strstr(str1, str2); +} + +char *osal_strnstr(char *str1, const char *str2, int n) +{ + return strnstr(str1, str2, n); +} + +void osal_bug_on(unsigned int val) +{ + WARN_ON(val); +} + +int osal_snprintf(char *buf, unsigned int len, const char *fmt, ...) +{ + int iRet = 0; + va_list args; + + /*va_start(args, fmt); */ + va_start(args, fmt); + /*iRet = snprintf(buf, len, fmt, args); */ + iRet = vsnprintf(buf, len, fmt, args); + va_end(args); + + return iRet; +} + +int osal_sprintf(char *str, const char *format, ...) +{ + int iRet = 0; + va_list args; + + va_start(args, format); + iRet = vsnprintf(str, DBG_LOG_STR_SIZE, format, args); + va_end(args); + + return iRet; +} + +void *osal_malloc(unsigned int size) +{ + return vmalloc(size); +} + +void osal_free(const void *dst) +{ + vfree(dst); +} + +void *osal_memset(void *buf, int i, unsigned int len) +{ + return memset(buf, i, len); +} + +void *osal_memcpy(void *dst, const void *src, unsigned int len) +{ + return memcpy(dst, src, len); +} + +void osal_memcpy_fromio(void *dst, const void *src, unsigned int len) +{ + return memcpy_fromio(dst, src, len); +} + +void osal_memcpy_toio(void *dst, const void *src, unsigned int len) +{ + return memcpy_toio(dst, src, len); +} + +int osal_memcmp(const void *buf1, const void *buf2, unsigned int len) +{ + return memcmp(buf1, buf2, len); +} + +void osal_dump_thread_state(const unsigned char *name) +{ + //TODO + return; +} + +static inline bool __osal_is_valid_thread(P_OSAL_THREAD pThread) +{ + if ((pThread) && !IS_ERR_OR_NULL(pThread->pThread)) + return true; + else + return false; +} + +/* + * OSAL layer Thread Opeartion related APIs + * + */ +int osal_thread_create(P_OSAL_THREAD pThread) +{ + struct task_struct *task; + + if (!pThread) + return -1; + + task = kthread_create(pThread->pThreadFunc, + pThread->pThreadData, pThread->threadName); + if (IS_ERR(task)) { + pr_err("[%s] create %s thread fail\n", __func__, pThread->threadName); + return -1; + } + + pThread->pThread = task; + return 0; +} + +int osal_thread_run(P_OSAL_THREAD pThread) +{ + if (__osal_is_valid_thread(pThread)) { + wake_up_process(pThread->pThread); + return 0; + } else { + return -1; + } +} + +int osal_thread_stop(P_OSAL_THREAD pThread) +{ + int iRet; + + if (__osal_is_valid_thread(pThread)) { + iRet = kthread_stop(pThread->pThread); + pThread->pThread = NULL; + return iRet; + } + return -1; +} + +int osal_thread_should_stop(P_OSAL_THREAD pThread) +{ + if (__osal_is_valid_thread(pThread)) + return kthread_should_stop(); + else + return 1; + +} + +int osal_thread_wait_for_event(P_OSAL_THREAD pThread, + P_OSAL_EVENT pEvent, P_OSAL_EVENT_CHECKER pChecker) +{ + /* P_DEV_WMT pDevWmt;*/ + + if (__osal_is_valid_thread(pThread) && (pEvent) && (pChecker)) { + return wait_event_interruptible(pEvent->waitQueue, ( + osal_thread_should_stop(pThread) + || (*pChecker) (pThread))); + } + return -1; +} + +int osal_thread_destroy(P_OSAL_THREAD pThread) +{ + if (__osal_is_valid_thread(pThread)) { + kthread_stop(pThread->pThread); + pThread->pThread = NULL; + } + return 0; +} + +/* + * osal_thread_sched_retrieve + * Retrieve thread's current scheduling statistics and stored in output "sched". + * Return value: + * 0 : Schedstats successfully retrieved + * -1 : Kernel's schedstats feature not enabled + * -2 : pThread not yet initialized or sched is a NULL pointer + */ +static int osal_thread_sched_retrieve(P_OSAL_THREAD pThread, + P_OSAL_THREAD_SCHEDSTATS sched) +{ +#ifdef CONFIG_SCHEDSTATS + struct sched_entity se; + unsigned long long sec; + unsigned long usec; + + if (!sched) + return -2; + + /* always clear sched to simplify error handling at caller side */ + memset(sched, 0, sizeof(OSAL_THREAD_SCHEDSTATS)); + + if (!__osal_is_valid_thread(pThread)) + return -2; + + memcpy(&se, &pThread->pThread->se, sizeof(struct sched_entity)); + osal_get_local_time(&sec, &usec); + + sched->time = sec*1000 + usec/1000; + sched->exec = se.sum_exec_runtime; + sched->runnable = se.statistics.wait_sum; + sched->iowait = se.statistics.iowait_sum; + + return 0; +#else + /* always clear sched to simplify error handling at caller side */ + if (sched) + memset(sched, 0, sizeof(OSAL_THREAD_SCHEDSTATS)); + return -1; +#endif +} + +/* + * osal_thread_sched_mark + * Record the thread's current schedstats and stored + * in output "schedstats" parameter for profiling at + * later time. + * Return value: + * 0 : Schedstats successfully recorded + * -1 : Kernel's schedstats feature not enabled + * -2 : pThread not yet initialized or invalid parameters + */ +int osal_thread_sched_mark(P_OSAL_THREAD pThread, + P_OSAL_THREAD_SCHEDSTATS schedstats) +{ + return osal_thread_sched_retrieve(pThread, schedstats); +} + +/* + * osal_thread_sched_unmark + * Calculate scheduling statistics against the previously marked point. + * The result will be filled back into the schedstats output parameter. + * Return value: + * 0 : Schedstats successfully calculated + * -1 : Kernel's schedstats feature not enabled + * -2 : pThread not yet initialized or invalid parameters + */ +int osal_thread_sched_unmark(P_OSAL_THREAD pThread, + P_OSAL_THREAD_SCHEDSTATS schedstats) +{ + int ret; + OSAL_THREAD_SCHEDSTATS sched_now; + + if (unlikely(!schedstats)) { + ret = -2; + } else { + ret = osal_thread_sched_retrieve(pThread, &sched_now); + if (ret == 0) { + schedstats->time = sched_now.time - schedstats->time; + schedstats->exec = sched_now.exec - schedstats->exec; + schedstats->runnable = + sched_now.runnable - schedstats->runnable; + schedstats->iowait = + sched_now.iowait - schedstats->iowait; + } + } + return ret; +} + +/* + * OSAL layer Signal Opeartion related APIs + * initialization + * wait for signal + * wait for signal timerout + * raise signal + * destroy a signal + * + */ + +int osal_signal_init(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) { + init_completion(&pSignal->comp); + return 0; + } else { + return -1; + } +} + +int osal_wait_for_signal(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) { + wait_for_completion_interruptible(&pSignal->comp); + return 0; + } else { + return -1; + } +} + +/* + * osal_wait_for_signal_timeout + * + * Wait for a signal to be triggered by the corresponding thread, within the + * expected timeout specified by the signal's timeoutValue. + * When the pThread parameter is specified, the thread's scheduling ability is + * considered, the timeout will be extended when thread cannot acquire CPU + * resource, and will only extend for a number of times specified by the + * signal's timeoutExtension should the situation continues. + * + * Return value: + * 0 : timeout + * >0 : signal triggered + */ +int osal_wait_for_signal_timeout(P_OSAL_SIGNAL pSignal, P_OSAL_THREAD pThread) +{ + OSAL_THREAD_SCHEDSTATS schedstats; + int waitRet; + + /* [ChangeFeature][George] gps driver may be closed by -ERESTARTSYS. + * Avoid using *interruptible" version in order to complete our jobs, + * such as function off gracefully. + */ + if (!pThread || !pThread->pThread) + return wait_for_completion_timeout(&pSignal->comp, + msecs_to_jiffies(pSignal->timeoutValue)); + + do { + osal_thread_sched_mark(pThread, &schedstats); + waitRet = wait_for_completion_timeout(&pSignal->comp, + msecs_to_jiffies(pSignal->timeoutValue)); + osal_thread_sched_unmark(pThread, &schedstats); + + if (waitRet > 0) + break; + + if (schedstats.runnable > schedstats.exec) { + pr_err( + "[E]%s:wait completion timeout, %s cannot get CPU, extension(%d), show backtrace:\n", + __func__, + pThread->threadName, + pSignal->timeoutExtension); + } else { + pr_err( + "[E]%s:wait completion timeout, show %s backtrace:\n", + __func__, + pThread->threadName); + pSignal->timeoutExtension = 0; + } + pr_err( + "[E]%s:\tduration:%llums, sched(x%llu/r%llu/i%llu)\n", + __func__, + schedstats.time, + schedstats.exec, + schedstats.runnable, + schedstats.iowait); + /* + * no need to disginguish combo or A/D die projects + * osal_dump_thread_state will just return if target + * thread does not exist + */ + osal_dump_thread_state("mtk_wmtd"); + osal_dump_thread_state("mtk_wmtd_worker"); + osal_dump_thread_state("btif_rxd"); + osal_dump_thread_state("mtk_stp_psm"); + osal_dump_thread_state("mtk_stp_btm"); + osal_dump_thread_state("stp_sdio_tx_rx"); + } while (pSignal->timeoutExtension--); + return waitRet; +} + +int osal_raise_signal(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) { + complete(&pSignal->comp); + return 0; + } else + return -1; +} + +int osal_signal_active_state(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) + return pSignal->timeoutValue; + else + return -1; +} + +int osal_signal_deinit(P_OSAL_SIGNAL pSignal) +{ + if (pSignal) { + pSignal->timeoutValue = 0; + return 0; + } else + return -1; +} + +/* + * OSAL layer Event Opeartion related APIs + * initialization + * wait for signal + * wait for signal timerout + * raise signal + * destroy a signal + * + */ + +int osal_event_init(P_OSAL_EVENT pEvent) +{ + if (pEvent) { + init_waitqueue_head(&pEvent->waitQueue); + return 0; + } + return -1; +} + +int osal_trigger_event(P_OSAL_EVENT pEvent) +{ + int ret = 0; + + if (pEvent) { + wake_up_interruptible(&pEvent->waitQueue); + return ret; + } + return -1; +} + +int osal_wait_for_event(P_OSAL_EVENT pEvent, + int (*condition)(void *), void *cond_pa) +{ + if (pEvent) + return wait_event_interruptible(pEvent->waitQueue, + condition(cond_pa)); + else + return -1; +} + +int osal_wait_for_event_timeout(P_OSAL_EVENT pEvent, + int (*condition)(void *), void *cond_pa) +{ + if (pEvent) + return wait_event_interruptible_timeout(pEvent->waitQueue, + condition(cond_pa), + msecs_to_jiffies(pEvent->timeoutValue)); + return -1; +} + + +int osal_event_deinit(P_OSAL_EVENT pEvent) +{ + return 0; +} + +long osal_wait_for_event_bit_set(P_OSAL_EVENT pEvent, + unsigned long *pState, unsigned int bitOffset) +{ + unsigned int ms = 0; + + if (pEvent) { + ms = pEvent->timeoutValue; + if (ms != 0) + return wait_event_interruptible_timeout( + pEvent->waitQueue, + test_bit(bitOffset, pState), + msecs_to_jiffies(ms)); + else + return wait_event_interruptible(pEvent->waitQueue, + test_bit(bitOffset, pState)); + } else + return -1; + +} + +long osal_wait_for_event_bit_clr(P_OSAL_EVENT pEvent, + unsigned long *pState, unsigned int bitOffset) +{ + unsigned int ms = 0; + + if (pEvent) { + ms = pEvent->timeoutValue; + if (ms != 0) + return wait_event_interruptible_timeout( + pEvent->waitQueue, + !test_bit(bitOffset, pState), + msecs_to_jiffies(ms)); + else + return wait_event_interruptible(pEvent->waitQueue, + !test_bit(bitOffset, pState)); + } else + return -1; +} + +/* + * bit test and set/clear operations APIs + */ +#if OS_BIT_OPS_SUPPORT +#define osal_bit_op_lock(x) +#define osal_bit_op_unlock(x) +#else + +int osal_bit_op_lock(P_OSAL_UNSLEEPABLE_LOCK pLock) +{ + + return 0; +} + +int osal_bit_op_unlock(P_OSAL_UNSLEEPABLE_LOCK pLock) +{ + + return 0; +} +#endif +int osal_clear_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + osal_bit_op_lock(&(pData->opLock)); + clear_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return 0; +} + +int osal_set_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + osal_bit_op_lock(&(pData->opLock)); + set_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return 0; +} + +int osal_test_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + unsigned int iRet = 0; + + osal_bit_op_lock(&(pData->opLock)); + iRet = test_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; +} + +int osal_test_and_clear_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + unsigned int iRet = 0; + + osal_bit_op_lock(&(pData->opLock)); + iRet = test_and_clear_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; + +} + +int osal_test_and_set_bit(unsigned int bitOffset, P_OSAL_BIT_OP_VAR pData) +{ + unsigned int iRet = 0; + + osal_bit_op_lock(&(pData->opLock)); + iRet = test_and_set_bit(bitOffset, &pData->data); + osal_bit_op_unlock(&(pData->opLock)); + return iRet; +} + +int _osal_fifo_init(OSAL_FIFO *pFifo, unsigned char *buf, unsigned int size) +{ + struct kfifo *fifo = NULL; + int ret = -1; + + if (!pFifo) { + pr_err("pFifo must be !NULL\n"); + return -1; + } + if (pFifo->pFifoBody) { + pr_err("pFifo->pFifoBody must be NULL\n"); + pr_err("pFifo(0x%p), pFifo->pFifoBody(0x%p)\n", + pFifo, pFifo->pFifoBody); + return -1; + } + fifo = kzalloc(sizeof(struct kfifo), GFP_ATOMIC); + if (!buf) { + /*fifo's buffer is not ready, we allocate automatically */ + ret = kfifo_alloc(fifo, size, /*GFP_KERNEL */ GFP_ATOMIC); + } else { + if (is_power_of_2(size)) { + kfifo_init(fifo, buf, size); + ret = 0; + } else { + kfifo_free(fifo); + fifo = NULL; + ret = -1; + } + } + + pFifo->pFifoBody = fifo; + return (ret < 0) ? (-1) : (0); +} + +int _osal_fifo_deinit(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + kfifo_free(fifo); + + return 0; +} + +int _osal_fifo_size(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_size(fifo); + + return ret; +} + +/*returns unused bytes in fifo*/ +int _osal_fifo_avail_size(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_avail(fifo); + + return ret; +} + +/*returns used bytes in fifo*/ +int _osal_fifo_len(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_len(fifo); + + return ret; +} + +int _osal_fifo_is_empty(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_is_empty(fifo); + + return ret; +} + +int _osal_fifo_is_full(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + ret = kfifo_is_full(fifo); + + return ret; +} + +int _osal_fifo_data_in(OSAL_FIFO *pFifo, const void *buf, unsigned int len) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo && buf && (len <= _osal_fifo_avail_size(pFifo))) { + ret = kfifo_in(fifo, buf, len); + } else { + pr_err("%s: kfifo_in, error, len = %d, _osal_fifo_avail_size = %d, buf=%p\n", + __func__, len, _osal_fifo_avail_size(pFifo), buf); + + ret = 0; + } + + return ret; +} + +int _osal_fifo_data_out(OSAL_FIFO *pFifo, void *buf, unsigned int len) +{ + struct kfifo *fifo = NULL; + int ret = 0; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n" + , __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo && buf && (len <= _osal_fifo_len(pFifo))) { + ret = kfifo_out(fifo, buf, len); + } else { + pr_err("%s: kfifo_out, error, len = %d, osal_fifo_len = %d, buf=%p\n", + __func__, len, _osal_fifo_len(pFifo), buf); + + ret = 0; + } + + return ret; +} + +int _osal_fifo_reset(OSAL_FIFO *pFifo) +{ + struct kfifo *fifo = NULL; + + if (!pFifo || !pFifo->pFifoBody) { + pr_err("%s:pFifo = NULL or pFifo->pFifoBody = NULL, error\n", + __func__); + return -1; + } + + fifo = (struct kfifo *)pFifo->pFifoBody; + + if (fifo) + kfifo_reset(fifo); + + return 0; +} + +int osal_fifo_init(P_OSAL_FIFO pFifo, unsigned char *buffer, unsigned int size) +{ + if (!pFifo) { + pr_err("%s:pFifo = NULL, error\n", __func__); + return -1; + } + + pFifo->FifoInit = _osal_fifo_init; + pFifo->FifoDeInit = _osal_fifo_deinit; + pFifo->FifoSz = _osal_fifo_size; + pFifo->FifoAvailSz = _osal_fifo_avail_size; + pFifo->FifoLen = _osal_fifo_len; + pFifo->FifoIsEmpty = _osal_fifo_is_empty; + pFifo->FifoIsFull = _osal_fifo_is_full; + pFifo->FifoDataIn = _osal_fifo_data_in; + pFifo->FifoDataOut = _osal_fifo_data_out; + pFifo->FifoReset = _osal_fifo_reset; + + if (pFifo->pFifoBody != NULL) { + pr_err("%s:Because pFifo room is avialable, we clear the room and allocate them again.\n", __func__); + pFifo->FifoDeInit(pFifo->pFifoBody); + pFifo->pFifoBody = NULL; + } + + pFifo->FifoInit(pFifo, buffer, size); + + return 0; +} + +void osal_fifo_deinit(P_OSAL_FIFO pFifo) +{ + if (pFifo) + pFifo->FifoDeInit(pFifo); + else { + pr_err("%s:pFifo = NULL, error\n", __func__); + return; + } + kfree(pFifo->pFifoBody); +} + +int osal_fifo_reset(P_OSAL_FIFO pFifo) +{ + int ret = -1; + + if (pFifo) { + ret = pFifo->FifoReset(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = -1; + } + return ret; +} + +unsigned int osal_fifo_in(P_OSAL_FIFO pFifo, + unsigned char *buffer, unsigned int size) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoDataIn(pFifo, buffer, size); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +unsigned int osal_fifo_out(P_OSAL_FIFO pFifo, + unsigned char *buffer, unsigned int size) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoDataOut(pFifo, buffer, size); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +unsigned int osal_fifo_len(P_OSAL_FIFO pFifo) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoLen(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +unsigned int osal_fifo_sz(P_OSAL_FIFO pFifo) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoSz(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +unsigned int osal_fifo_avail(P_OSAL_FIFO pFifo) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoAvailSz(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +unsigned int osal_fifo_is_empty(P_OSAL_FIFO pFifo) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoIsEmpty(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + + return ret; +} + +unsigned int osal_fifo_is_full(P_OSAL_FIFO pFifo) +{ + unsigned int ret = 0; + + if (pFifo) { + ret = pFifo->FifoIsFull(pFifo); + } else { + pr_err("%s:pFifo = NULL, error\n", __func__); + ret = 0; + } + return ret; +} + +/* + * sleepable lock operations APIs + * init + * lock + * unlock + * destroy + * + */ +#if !defined(CONFIG_PROVE_LOCKING) +int osal_unsleepable_lock_init(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + spin_lock_init(&(pUSL->lock)); + return 0; +} +#endif + +int osal_lock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + spin_lock_irqsave(&(pUSL->lock), pUSL->flag); + return 0; +} + +int osal_unlock_unsleepable_lock(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + spin_unlock_irqrestore(&(pUSL->lock), pUSL->flag); + return 0; +} + +int osal_unsleepable_lock_deinit(P_OSAL_UNSLEEPABLE_LOCK pUSL) +{ + return 0; +} + +/* + * unsleepable operations APIs + * init + * lock + * unlock + * destroy + * + */ + +#if !defined(CONFIG_PROVE_LOCKING) +int osal_sleepable_lock_init(P_OSAL_SLEEPABLE_LOCK pSL) +{ + mutex_init(&pSL->lock); + return 0; +} +#endif + +int osal_lock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) +{ + return mutex_lock_killable(&pSL->lock); +} + +int osal_unlock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) +{ + mutex_unlock(&pSL->lock); + return 0; +} + +int osal_trylock_sleepable_lock(P_OSAL_SLEEPABLE_LOCK pSL) +{ + return mutex_trylock(&pSL->lock); +} + +int osal_sleepable_lock_deinit(P_OSAL_SLEEPABLE_LOCK pSL) +{ + mutex_destroy(&pSL->lock); + return 0; +} + +int osal_sleep_ms(unsigned int ms) +{ + msleep(ms); + return 0; +} + +int osal_udelay(unsigned int us) +{ + udelay(us); + return 0; +} + +int osal_usleep_range(unsigned long min, unsigned long max) +{ + usleep_range(min, max); + return 0; +} + +int osal_gettimeofday(int *sec, int *usec) +{ + int ret = 0; + struct timespec64 now; + + ktime_get_real_ts64(&now); + + if (sec != NULL) + *sec = now.tv_sec; + else + ret = -1; + + if (usec != NULL) + *usec = (now.tv_nsec / 1000); + else + ret = -1; + + return ret; +} + +int osal_gettimeofday2(struct timeval *tv) +{ + int ret = 0; + struct timespec64 now; + + if (tv == NULL) + return -1; + + ktime_get_real_ts64(&now); + tv->tv_sec = now.tv_sec; + tv->tv_usec = (now.tv_nsec / 1000); + return ret; +} + +void osal_get_local_time(unsigned long long *sec, unsigned long *nsec) +{ + if (sec != NULL && nsec != NULL) { + *sec = local_clock(); + *nsec = do_div(*sec, 1000000000)/1000; + } else + pr_err("The input parameters error when get local time\n"); +} + +unsigned long long osal_elapsed_us(unsigned long long ts, unsigned long usec) +{ + unsigned long long current_ts = 0; + unsigned long current_usec = 0; + + osal_get_local_time(¤t_ts, ¤t_usec); + return (current_ts*1000000 + current_usec) - (ts*1000000 + usec); +} + +void osal_buffer_dump(const unsigned char *buf, + const unsigned char *title, const unsigned int len, + const unsigned int limit) +{ + int k; + unsigned int dump_len; + char str[DBG_LOG_STR_SIZE] = {""}; + int strlen = 0; + + pr_info("[%s] len=%d, limit=%d, start dump\n", title, len, limit); + + dump_len = ((limit != 0) && (len > limit)) ? limit : len; + for (k = 0; k < dump_len; k++) { + if ((k+1) % 16 != 0) { + strlen += osal_snprintf(str + strlen, DBG_LOG_STR_SIZE - strlen, + "%02x ", buf[k]); + } else { + strlen += osal_snprintf(str + strlen, DBG_LOG_STR_SIZE - strlen, + "%02x ", buf[k]); + + pr_info("%s", str); + strlen = 0; + } + } + if (k % 16 != 0) + pr_info("%s\n", str); + + pr_info("end of dump\n"); +} + +void osal_buffer_dump_data(const unsigned int *buf, + const unsigned char *title, const unsigned int len, + const unsigned int limit, + const int flag) +{ + int k; + unsigned int dump_len; + char str[DBG_LOG_STR_SIZE] = {""}; + int strlen = 0; + + dump_len = ((limit != 0) && (len > limit)) ? limit : len; + for (k = 0; k < dump_len; k++) { + if (((k+1) % 8 != 0) && (k < (dump_len - 1))) { + strlen += osal_snprintf(str + strlen, DBG_LOG_STR_SIZE - strlen, + "0x%08x,", buf[k]); + } else { + strlen += osal_snprintf(str + strlen, DBG_LOG_STR_SIZE - strlen, + "0x%08x,", buf[k]); + if (flag) + osal_ftrace_print("%s%s", title, str); + else + pr_info("%s%s", title, str); + strlen = 0; + } + } + if (k % 8 != 0) { + if (flag) + osal_ftrace_print("%s%s", title, str); + else + pr_info("%s%s", title, str); + } +} + +unsigned int osal_op_get_id(P_OSAL_OP pOp) +{ + return (pOp) ? pOp->op.opId : 0xFFFFFFFF; +} + +MTK_CONN_BOOL osal_op_is_wait_for_signal(P_OSAL_OP pOp) +{ + return (pOp && pOp->signal.timeoutValue) + ? MTK_CONN_BOOL_TRUE : MTK_CONN_BOOL_FALSE; +} + +void osal_op_raise_signal(P_OSAL_OP pOp, int result) +{ + if (pOp) { + pOp->result = result; + osal_raise_signal(&pOp->signal); + } +} + +int osal_ftrace_print(const char *str, ...) +{ +#ifdef CONFIG_TRACING + va_list args; + char tempString[DBG_LOG_STR_SIZE]; + + if (ftrace_flag) { + va_start(args, str); + vsnprintf(tempString, DBG_LOG_STR_SIZE, str, args); + va_end(args); + + trace_printk("%s\n", tempString); + } +#endif + return 0; +} + +int osal_ftrace_print_ctrl(int flag) +{ +#ifdef CONFIG_TRACING + if (flag) + ftrace_flag = 1; + else + ftrace_flag = 0; +#endif + return 0; +} + +void osal_set_op_result(P_OSAL_OP pOp, int result) +{ + if (pOp) + pOp->result = result; + +} + +static void _osal_opq_dump(const char *qName, P_OSAL_OP_Q pOpQ) +{ + /* Line format: + * [LogicalIdx(PhysicalIdx)]Address:OpId(Ref)(Result)-Info-OpData0,OpData1,OpData2,OpData3,OpData5_ + * [LogicalIdx] max 10+2=12 chars (decimal) + * (PhysicalIdx) max 10+2=12 chars (decimal) + * Address: max 16+1=17 chars (hex) + * OpId max 10 chars (decimal) + * (Ref) max 2+2=4 chars (should only be 1 digit, reserve 2 in case of negative number) + * (Result) max 11+2=13 chars (signed decimal) + * -Info- max 8+2=10 chars (hex) + * OpData, max 16+1=17 chars (hex) + */ +#define OPQ_DUMP_OP_PER_LINE 1 +#define OPQ_DUMP_OPDATA_PER_OP 6 +#define OPQ_DUMP_OP_BUF_SIZE (12 + 12 + 17 + 10 + 4 + 13 + 10 + (17 * (OPQ_DUMP_OPDATA_PER_OP)) + 1) +#define OPQ_DUMP_LINE_BUF_SIZE ((OPQ_DUMP_OP_BUF_SIZE * OPQ_DUMP_OP_PER_LINE) + 1) + unsigned int rd; + unsigned int wt; + unsigned int idx = 0; + unsigned int opDataIdx; + unsigned int idxInBuf; + int printed; + P_OSAL_OP op; + char buf[OPQ_DUMP_LINE_BUF_SIZE]; + + rd = pOpQ->read; + wt = pOpQ->write; + + pr_info("%s(%p), sz:%u/%u, rd:%u, wt:%u\n", + qName, pOpQ, RB_COUNT(pOpQ), RB_SIZE(pOpQ), rd, wt); + while (rd != wt && idx < RB_SIZE(pOpQ)) { + idxInBuf = idx % OPQ_DUMP_OP_PER_LINE; + op = pOpQ->queue[rd & RB_MASK(pOpQ)]; + + if (idxInBuf == 0) { + printed = 0; + buf[0] = 0; + } + + if (op) { + printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed, + "[%u(%u)]%p:%u(%d)(%d)-%u-", + idx, + (rd & RB_MASK(pOpQ)), + op, + op->op.opId, + atomic_read(&op->ref_count), + op->result, + op->op.u4InfoBit); + for (opDataIdx = 0; opDataIdx < OPQ_DUMP_OPDATA_PER_OP; opDataIdx++) + printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed, + "%zx,", op->op.au4OpData[opDataIdx]); + buf[printed-1] = ' '; + } else { + printed += snprintf(buf + printed, OPQ_DUMP_LINE_BUF_SIZE - printed, + "[%u(%u)]%p ", idx, (rd & RB_MASK(pOpQ)), op); + } + buf[printed++] = ' '; + + if (idxInBuf == OPQ_DUMP_OP_PER_LINE - 1 || rd == wt - 1) { + buf[printed - 1] = 0; + pr_info("%s\n", buf); + } + rd++; + idx++; + } +} + +void osal_opq_dump(const char *qName, P_OSAL_OP_Q pOpQ) +{ + int err; + + err = osal_lock_sleepable_lock(&pOpQ->sLock); + if (err) { + pr_info("Failed to lock queue (%d)\n", err); + return; + } + + _osal_opq_dump(qName, pOpQ); + + osal_unlock_sleepable_lock(&pOpQ->sLock); +} + +void osal_opq_dump_locked(const char *qName, P_OSAL_OP_Q pOpQ) +{ + _osal_opq_dump(qName, pOpQ); +} + +MTK_CONN_BOOL osal_opq_has_op(P_OSAL_OP_Q pOpQ, P_OSAL_OP pOp) +{ + unsigned int rd; + unsigned int wt; + P_OSAL_OP op; + + rd = pOpQ->read; + wt = pOpQ->write; + + while (rd != wt) { + op = pOpQ->queue[rd & RB_MASK(pOpQ)]; + if (op == pOp) + return MTK_CONN_BOOL_TRUE; + rd++; + } + return MTK_CONN_BOOL_FALSE; +} + +static void osal_op_history_print_work(struct work_struct *work) +{ + struct osal_op_history *log_history + = container_of(work, struct osal_op_history, dump_work); + struct ring *ring_buffer = &log_history->dump_ring_buffer; + struct ring_segment seg; + struct osal_op_history_entry *queue = ring_buffer->base; + struct osal_op_history_entry *entry; + int index = 0; + + if (queue == NULL) { + pr_info("queue shouldn't be NULL, %s", log_history->name); + return; + } + + if (RING_EMPTY(ring_buffer)) + pr_info("History of %s is empty.\n", log_history->name); + + RING_READ_FOR_EACH_ITEM(RING_SIZE(ring_buffer), seg, ring_buffer) { + index = seg.ring_pt - ring_buffer->base; + entry = &queue[index]; + pr_info("(%llu.%06lu) %s: pOp(%p):%u(%d)-%x-%zx,%zx,%zx,%zx\n", + entry->ts, + entry->usec, + log_history->name, + entry->opbuf_address, + entry->op_id, + entry->opbuf_ref_count, + entry->op_info_bit, + entry->param_0, + entry->param_1, + entry->param_2, + entry->param_3); + } + kfree(queue); + ring_buffer->base = NULL; +} + +void osal_op_history_init(struct osal_op_history *log_history, int queue_size) +{ + int size = queue_size * sizeof(struct osal_op_history_entry); + + spin_lock_init(&(log_history->lock)); + + log_history->queue = kzalloc(size, GFP_ATOMIC); + if (log_history->queue == NULL) + return; + + /* queue_size must be power of 2 */ + ring_init( + &log_history->queue, + queue_size, + 0, + 0, + &log_history->ring_buffer); + + INIT_WORK(&log_history->dump_work, osal_op_history_print_work); +} + +void osal_op_history_print(struct osal_op_history *log_history, char *name) +{ + struct osal_op_history_entry *queue; + struct ring *ring_buffer, *dump_ring_buffer; + int queue_size; + unsigned long flags; + struct work_struct *work = &log_history->dump_work; + spinlock_t *lock = &(log_history->lock); + + if (log_history->queue == NULL) { + pr_info("Queue is NULL, name: %s\n", name); + return; + } + + ring_buffer = &log_history->ring_buffer; + queue_size = sizeof(struct osal_op_history_entry) + * RING_SIZE(ring_buffer); + + /* Allocate memory before getting lock to save time of holding lock */ + queue = kmalloc(queue_size, GFP_KERNEL); + if (queue == NULL) + return; + + dump_ring_buffer = &log_history->dump_ring_buffer; + + spin_lock_irqsave(lock, flags); + if (dump_ring_buffer->base != NULL) { + spin_unlock_irqrestore(lock, flags); + kfree(queue); + pr_info("print is ongoing: %s\n", name); + return; + } + + osal_snprintf(log_history->name, sizeof(log_history->name), "%s", name); + osal_memcpy(queue, log_history->queue, queue_size); + osal_memcpy(dump_ring_buffer, ring_buffer, sizeof(struct ring)); + /* assign value to base after memory copy */ + dump_ring_buffer->base = queue; + spin_unlock_irqrestore(lock, flags); + schedule_work(work); +} + +void osal_op_history_save(struct osal_op_history *log_history, P_OSAL_OP pOp) +{ + struct osal_op_history_entry *entry = NULL; + struct ring_segment seg; + int index; + unsigned long long sec = 0; + unsigned long usec = 0; + unsigned long flags; + + if (log_history->queue == NULL) + return; + + osal_get_local_time(&sec, &usec); + + spin_lock_irqsave(&(log_history->lock), flags); + RING_OVERWRITE_FOR_EACH(1, seg, &log_history->ring_buffer) { + index = seg.ring_pt - log_history->ring_buffer.base; + entry = &log_history->queue[index]; + } + + if (entry == NULL) { + pr_info("Entry is null, size %d\n", + RING_SIZE(&log_history->ring_buffer)); + spin_unlock_irqrestore(&(log_history->lock), flags); + return; + } + + entry->opbuf_address = pOp; + entry->op_id = pOp->op.opId; + entry->opbuf_ref_count = atomic_read(&pOp->ref_count); + entry->op_info_bit = pOp->op.u4InfoBit; + entry->param_0 = pOp->op.au4OpData[0]; + entry->param_1 = pOp->op.au4OpData[1]; + entry->param_2 = pOp->op.au4OpData[2]; + entry->param_3 = pOp->op.au4OpData[3]; + entry->ts = sec; + entry->usec = usec; + spin_unlock_irqrestore(&(log_history->lock), flags); +} + diff --git a/package/mtk/drivers/conninfra/src/base/ring.c b/package/mtk/drivers/conninfra/src/base/ring.c new file mode 100644 index 0000000000..24cad3b7f9 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/base/ring.c @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +#include "ring.h" +#include +#include +#include + + +void ring_init(void *base, unsigned int max_size, unsigned int read, + unsigned int write, struct ring *ring) +{ + WARN_ON(!base); + + /* making sure max_size is power of 2 */ + WARN_ON(!max_size || (max_size & (max_size - 1))); + + /* making sure write largger than read */ + WARN_ON(read > write); + + ring->base = base; + ring->read = read; + ring->write = write; + ring->max_size = max_size; +} + +void ring_dump(const char *title, struct ring *ring) +{ + pr_info("[%s] ring:{write=%d, read=%d, max_size=%d}\n", + title, ring->write, ring->read, ring->max_size); +} + +void ring_dump_segment(const char *title, struct ring_segment *seg) +{ + pr_info("[%s] seg:{ring_pt=0x%p, data_pos=%d, sz=%d, remain=%d}\n", + title, seg->ring_pt, seg->data_pos, + seg->sz, seg->remain); +} + +/* + * Function prepares the ring_segment and + * returns the number of valid bytes for read. + */ +unsigned int ring_read_prepare(unsigned int sz, + struct ring_segment *seg, + struct ring *ring) +{ + unsigned int wt = ring->write; + unsigned int rd = ring->read; + + memset(seg, 0, sizeof(struct ring_segment)); + if (sz > wt - rd) + sz = wt - rd; + seg->remain = sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ + return seg->remain; +} + +/* + * Function prepares the ring_segment and + * returns the number of bytes available for write. + */ +unsigned int ring_write_prepare(unsigned int sz, + struct ring_segment *seg, + struct ring *ring) +{ + unsigned int wt = ring->write; + unsigned int rd = ring->read; + + memset(seg, 0, sizeof(struct ring_segment)); + if (sz > ring->max_size - (wt - rd)) + sz = ring->max_size - (wt - rd); + seg->remain = sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ + return seg->remain; +} + +unsigned int ring_overwrite_prepare(unsigned int sz, struct ring_segment *seg, + struct ring *ring) +{ + unsigned int wt = ring->write; + unsigned int rd = ring->read; + + memset(seg, 0, sizeof(struct ring_segment)); + if (sz > ring->max_size - (wt - rd)) + ring->read += sz - (ring->max_size - (wt - rd)); + seg->remain = sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ + return seg->remain; +} + +void __ring_segment_prepare(unsigned int from, unsigned int sz, + struct ring_segment *seg, + struct ring *ring) +{ + unsigned int ring_pos = from & (ring->max_size - 1); + + seg->ring_pt = ring->base + ring_pos; + seg->data_pos = (seg->sz ? seg->data_pos + seg->sz : 0); + if (ring_pos + sz <= ring->max_size) + seg->sz = sz; + else + seg->sz = ring->max_size - ring_pos; + seg->remain -= seg->sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ +} + +void _ring_segment_prepare(unsigned int from, + struct ring_segment *seg, + struct ring *ring) +{ + __ring_segment_prepare(from, seg->remain, seg, ring); +} + +void _ring_segment_prepare_item(unsigned int from, + struct ring_segment *seg, + struct ring *ring) +{ + unsigned int size; + + size = (seg->remain ? 1 : 0); + __ring_segment_prepare(from, size, seg, ring); +} + +void _ring_read_commit(struct ring_segment *seg, struct ring *ring) +{ + ring->read += seg->sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ +} +void _ring_write_commit(struct ring_segment *seg, struct ring *ring) +{ + ring->write += seg->sz; + /* ring_dump(__func__, ring); */ + /* ring_dump_segment(__func__, seg); */ +} + diff --git a/package/mtk/drivers/conninfra/src/core/conninfra_core.c b/package/mtk/drivers/conninfra/src/core/conninfra_core.c new file mode 100644 index 0000000000..0f0a771309 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/core/conninfra_core.c @@ -0,0 +1,1244 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include "consys_hw.h" +#include "conninfra_core.h" +#include "msg_thread.h" +#include "consys_reg_mng.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define CONNINFRA_EVENT_TIMEOUT 3000 +#define CONNINFRA_RESET_TIMEOUT 500 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static int opfunc_power_on(struct msg_op_data *op); +static int opfunc_power_off(struct msg_op_data *op); +static int opfunc_chip_rst(struct msg_op_data *op); +static int opfunc_rfspi_read(struct msg_op_data *op); +static int opfunc_rfspi_write(struct msg_op_data *op); +static int opfunc_adie_top_ck_en_on(struct msg_op_data *op); +static int opfunc_adie_top_ck_en_off(struct msg_op_data *op); +static int opfunc_spi_clock_switch(struct msg_op_data *op); +static int opfunc_force_conninfra_wakeup(struct msg_op_data *op); +static int opfunc_force_conninfra_sleep(struct msg_op_data *op); +static int opfunc_dump_power_state(struct msg_op_data *op); +static int opfunc_subdrv_pre_reset(struct msg_op_data *op); +static int opfunc_subdrv_post_reset(struct msg_op_data *op); +static void _conninfra_core_update_rst_status(enum chip_rst_status status); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +struct conninfra_ctx g_conninfra_ctx; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ +static const msg_opid_func conninfra_core_opfunc[] = { + [CONNINFRA_OPID_PWR_ON] = opfunc_power_on, + [CONNINFRA_OPID_PWR_OFF] = opfunc_power_off, + [CONNINFRA_OPID_RFSPI_READ] = opfunc_rfspi_read, + [CONNINFRA_OPID_RFSPI_WRITE] = opfunc_rfspi_write, + [CONNINFRA_OPID_ADIE_TOP_CK_EN_ON] = opfunc_adie_top_ck_en_on, + [CONNINFRA_OPID_ADIE_TOP_CK_EN_OFF] = opfunc_adie_top_ck_en_off, + [CONNINFRA_OPID_SPI_CLOCK_SWITCH] = opfunc_spi_clock_switch, + [CONNINFRA_OPID_FORCE_CONNINFRA_WAKUP] = opfunc_force_conninfra_wakeup, + [CONNINFRA_OPID_FORCE_CONNINFRA_SLEEP] = opfunc_force_conninfra_sleep, + [CONNINFRA_OPID_DUMP_POWER_STATE] = opfunc_dump_power_state, +}; + +static const msg_opid_func conninfra_core_cb_opfunc[] = { + [CONNINFRA_CB_OPID_CHIP_RST] = opfunc_chip_rst, +}; + + +/* subsys ops */ +static char *drv_thread_name[] = { + [CONNDRV_TYPE_BT] = "sub_bt_thrd", + [CONNDRV_TYPE_FM] = "sub_fm_thrd", + [CONNDRV_TYPE_GPS] = "sub_gps_thrd", + [CONNDRV_TYPE_WIFI] = "sub_wifi_thrd", + [CONNDRV_TYPE_CONNINFRA] = "sub_conninfra_thrd", +}; + +static char *drv_name[] = { + [CONNDRV_TYPE_BT] = "BT", + [CONNDRV_TYPE_FM] = "FM", + [CONNDRV_TYPE_GPS] = "GPS", + [CONNDRV_TYPE_WIFI] = "WIFI", + [CONNDRV_TYPE_CONNINFRA] = "CONNINFRA", +}; + +typedef enum { + INFRA_SUBDRV_OPID_PRE_RESET = 0, + INFRA_SUBDRV_OPID_POST_RESET = 1, + INFRA_SUBDRV_OPID_MAX +} infra_subdrv_op; + + +static const msg_opid_func infra_subdrv_opfunc[] = { + [INFRA_SUBDRV_OPID_PRE_RESET] = opfunc_subdrv_pre_reset, + [INFRA_SUBDRV_OPID_POST_RESET] = opfunc_subdrv_post_reset, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +static void reset_chip_rst_trg_data(void) +{ + g_conninfra_ctx.trg_drv = CONNDRV_TYPE_MAX; + memset(g_conninfra_ctx.trg_reason, '\0', CHIP_RST_REASON_MAX_LEN); +} + +static unsigned long timeval_to_ms(struct timeval *begin, struct timeval *end) +{ + unsigned long time_diff; + + time_diff = (end->tv_sec - begin->tv_sec) * 1000; + time_diff += (end->tv_usec - begin->tv_usec) / 1000; + + return time_diff; +} + +static unsigned int opfunc_get_current_status(void) +{ + unsigned int ret = 0; + unsigned int i; + + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + ret |= (g_conninfra_ctx.drv_inst[i].drv_status << i); + } + + return ret; +} + +static void opfunc_vcn_control_internal(unsigned int drv_type, bool on) +{ + /* VCNx enable */ + switch (drv_type) { + case CONNDRV_TYPE_BT: + consys_hw_bt_power_ctl(on); + break; + case CONNDRV_TYPE_FM: + consys_hw_fm_power_ctl(on); + break; + case CONNDRV_TYPE_GPS: + consys_hw_gps_power_ctl(on); + break; + case CONNDRV_TYPE_WIFI: + consys_hw_wifi_power_ctl(on); + break; + case CONNDRV_TYPE_CONNINFRA: + break; + default: + pr_err("Wrong parameter: drv_type(%d)\n", drv_type); + break; + } +} + +static int opfunc_power_on_internal(unsigned int drv_type) +{ + int ret; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + /* Check abnormal type */ + if (drv_type >= CONNDRV_TYPE_MAX) { + pr_err("abnormal Fun(%d)\n", drv_type); + return -EINVAL; + } + + /* Check abnormal state */ + if ((g_conninfra_ctx.drv_inst[drv_type].drv_status < DRV_STS_POWER_OFF) + || (g_conninfra_ctx.drv_inst[drv_type].drv_status >= DRV_STS_MAX)) { + pr_err("func(%d) status[0x%x] abnormal\n", drv_type, + g_conninfra_ctx.drv_inst[drv_type].drv_status); + return -EINVAL; + } + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return ret; + } + + /* check if func already on */ + if (g_conninfra_ctx.drv_inst[drv_type].drv_status == DRV_STS_POWER_ON) { + pr_warn("func(%d) already on\n", drv_type); + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return 0; + } + + ret = consys_hw_pwr_on(opfunc_get_current_status(), drv_type); + if (ret) { + pr_err("Conninfra power on fail. drv(%d) ret=(%d)\n", + drv_type, ret); + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return -3; + } + + /* POWER ON SEQUENCE */ + g_conninfra_ctx.infra_drv_status = DRV_STS_POWER_ON; + g_conninfra_ctx.drv_inst[drv_type].drv_status = DRV_STS_POWER_ON; + + /* VCNx enable */ + opfunc_vcn_control_internal(drv_type, true); + + pr_info("[Conninfra Pwr On] BT=[%d] FM=[%d] GPS=[%d] WF=[%d] CONNINFRA=[%d]\n", + infra_ctx->drv_inst[CONNDRV_TYPE_BT].drv_status, + infra_ctx->drv_inst[CONNDRV_TYPE_FM].drv_status, + infra_ctx->drv_inst[CONNDRV_TYPE_GPS].drv_status, + infra_ctx->drv_inst[CONNDRV_TYPE_WIFI].drv_status, + infra_ctx->drv_inst[CONNDRV_TYPE_CONNINFRA].drv_status); + + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + + return 0; +} + +static int opfunc_power_on(struct msg_op_data *op) +{ + unsigned int drv_type = op->op_data[0]; + + return opfunc_power_on_internal(drv_type); +} + +static int opfunc_power_off_internal(unsigned int drv_type) +{ + int i, ret; + bool try_power_off = true; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + unsigned int curr_status = opfunc_get_current_status(); + + /* Check abnormal type */ + if (drv_type >= CONNDRV_TYPE_MAX) { + pr_err("abnormal Fun(%d)\n", drv_type); + return -EINVAL; + } + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return ret; + } + + /* Check abnormal state */ + if ((g_conninfra_ctx.drv_inst[drv_type].drv_status < DRV_STS_POWER_OFF) + || (g_conninfra_ctx.drv_inst[drv_type].drv_status >= DRV_STS_MAX)) { + pr_err("func(%d) status[0x%x] abnormal\n", drv_type, + g_conninfra_ctx.drv_inst[drv_type].drv_status); + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return -2; + } + + /* Special case for force power off */ + if (drv_type == CONNDRV_TYPE_CONNINFRA) { + if (g_conninfra_ctx.infra_drv_status == DRV_STS_POWER_OFF) { + pr_warn("Connsys already off, do nothing for force off\n"); + return 0; + } + /* Turn off subsys VCN and update record */ + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + if (g_conninfra_ctx.drv_inst[i].drv_status == DRV_STS_POWER_ON) { + opfunc_vcn_control_internal(i, false); + g_conninfra_ctx.drv_inst[i].drv_status = DRV_STS_POWER_OFF; + } + } + /* POWER OFF SEQUENCE */ + ret = consys_hw_pwr_off(0, drv_type); + /* For force power off operation, ignore err code */ + if (ret) + pr_err("Force power off fail. ret=%d\n", ret); + try_power_off = true; + } else { + /* check if func already off */ + if (g_conninfra_ctx.drv_inst[drv_type].drv_status + == DRV_STS_POWER_OFF) { + pr_warn("func(%d) already off\n", drv_type); + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return 0; + } + /* VCNx disable */ + opfunc_vcn_control_internal(drv_type, false); + g_conninfra_ctx.drv_inst[drv_type].drv_status = DRV_STS_POWER_OFF; + /* is there subsys on ? */ + for (i = 0; i < CONNDRV_TYPE_MAX; i++) + if (g_conninfra_ctx.drv_inst[i].drv_status == DRV_STS_POWER_ON) + try_power_off = false; + + /* POWER OFF SEQUENCE */ + ret = consys_hw_pwr_off(curr_status, drv_type); + if (ret) { + pr_err("Conninfra power on fail. drv(%d) ret=(%d)\n", + drv_type, ret); + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return -3; + } + } + + if (try_power_off) + g_conninfra_ctx.infra_drv_status = DRV_STS_POWER_OFF; + + pr_info("[Conninfra Pwr Off] Conninfra=[%d] BT=[%d] FM=[%d] GPS=[%d] WF=[%d]\n", + infra_ctx->infra_drv_status, + infra_ctx->drv_inst[CONNDRV_TYPE_BT].drv_status, + infra_ctx->drv_inst[CONNDRV_TYPE_FM].drv_status, + infra_ctx->drv_inst[CONNDRV_TYPE_GPS].drv_status, + infra_ctx->drv_inst[CONNDRV_TYPE_WIFI].drv_status); + + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return 0; +} + +static int opfunc_power_off(struct msg_op_data *op) +{ + unsigned int drv_type = op->op_data[0]; + + return opfunc_power_off_internal(drv_type); +} + +static int opfunc_chip_rst(struct msg_op_data *op) +{ + int i, ret, cur_rst_state; + struct subsys_drv_inst *drv_inst; + unsigned int drv_pwr_state[CONNDRV_TYPE_MAX]; + const unsigned int subdrv_all_done = (0x1 << CONNDRV_TYPE_MAX) - 1; + struct timeval pre_begin, pre_end, reset_end, done_end; + + if (g_conninfra_ctx.infra_drv_status == DRV_STS_POWER_OFF) { + pr_info("No subsys on, just return\n"); + _conninfra_core_update_rst_status(CHIP_RST_NONE); + return 0; + } + + osal_gettimeofday2(&pre_begin); + + atomic_set(&g_conninfra_ctx.rst_state, 0); + sema_init(&g_conninfra_ctx.rst_sema, 1); + + _conninfra_core_update_rst_status(CHIP_RST_PRE_CB); + + /* pre */ + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + drv_inst = &g_conninfra_ctx.drv_inst[i]; + drv_pwr_state[i] = drv_inst->drv_status; + pr_info("subsys %d is %d\n", i, drv_inst->drv_status); + ret = msg_thread_send_1(&drv_inst->msg_ctx, INFRA_SUBDRV_OPID_PRE_RESET, i); + } + + pr_info("[chip_rst] pre vvvvvvvvvvvvv\n"); + while (atomic_read(&g_conninfra_ctx.rst_state) != subdrv_all_done) { + ret = down_timeout(&g_conninfra_ctx.rst_sema, msecs_to_jiffies(CONNINFRA_RESET_TIMEOUT)); + pr_info("sema ret=[%d]\n", ret); + if (ret == 0) + continue; + cur_rst_state = atomic_read(&g_conninfra_ctx.rst_state); + pr_info("cur_rst state =[%d]\n", cur_rst_state); + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + if ((cur_rst_state & (0x1 << i)) == 0) { + pr_info("[chip_rst] [%s] pre-callback is not back\n", drv_thread_name[i]); + } + } + } + + _conninfra_core_update_rst_status(CHIP_RST_RESET); + + osal_gettimeofday2(&pre_end); + + pr_info("[chip_rst] reset ++++++++++++\n"); + /*******************************************************/ + /* reset */ + /* call consys_hw */ + /*******************************************************/ + /* Special power-off function, turn off connsys directly */ + ret = opfunc_power_off_internal(CONNDRV_TYPE_CONNINFRA); + pr_info("Force conninfra power off, ret=%d\n", ret); + pr_info("conninfra status should be power off. Status=%d\n", g_conninfra_ctx.infra_drv_status); + + /* Turn on subsys */ + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + if (drv_pwr_state[i]) { + ret = opfunc_power_on_internal(i); + pr_info("Call subsys(%d) power on ret=%d\n", i, ret); + } + } + pr_info("conninfra status should be power on. Status=%d\n", g_conninfra_ctx.infra_drv_status); + + pr_info("[chip_rst] reset --------------\n"); + + _conninfra_core_update_rst_status(CHIP_RST_POST_CB); + + osal_gettimeofday2(&reset_end); + + /* post */ + atomic_set(&g_conninfra_ctx.rst_state, 0); + sema_init(&g_conninfra_ctx.rst_sema, 1); + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + drv_inst = &g_conninfra_ctx.drv_inst[i]; + ret = msg_thread_send_1(&drv_inst->msg_ctx, INFRA_SUBDRV_OPID_POST_RESET, i); + } + + while (atomic_read(&g_conninfra_ctx.rst_state) != subdrv_all_done) { + ret = down_timeout(&g_conninfra_ctx.rst_sema, msecs_to_jiffies(CONNINFRA_RESET_TIMEOUT)); + if (ret == 0) + continue; + cur_rst_state = atomic_read(&g_conninfra_ctx.rst_state); + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + if ((cur_rst_state & (0x1 << i)) == 0) { + pr_info("[chip_rst] [%s] post-callback is not back\n", drv_thread_name[i]); + } + } + } + pr_info("[chip_rst] post ^^^^^^^^^^^^^^\n"); + + reset_chip_rst_trg_data(); + //_conninfra_core_update_rst_status(CHIP_RST_DONE); + _conninfra_core_update_rst_status(CHIP_RST_NONE); + osal_gettimeofday2(&done_end); + + pr_info("[chip_rst] summary pre=[%lu] reset=[%lu] post=[%lu]\n", + timeval_to_ms(&pre_begin, &pre_end), + timeval_to_ms(&pre_end, &reset_end), + timeval_to_ms(&reset_end, &done_end)); + + return 0; +} + +static int opfunc_rfspi_read(struct msg_op_data *op) +{ + int ret = 0; + unsigned int data = 0; + unsigned int* data_pt = (unsigned int*)op->op_data[2]; + + ret = osal_lock_sleepable_lock(&g_conninfra_ctx.core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return CONNINFRA_SPI_OP_FAIL; + } + + if (g_conninfra_ctx.infra_drv_status != DRV_STS_POWER_ON) { + pr_err("Connsys didn't power on\n"); + ret = CONNINFRA_SPI_OP_FAIL; + goto err; + } + + if (consys_hw_reg_readable() == 0) { + pr_err("connsys reg not readable\n"); + ret = CONNINFRA_SPI_OP_FAIL; + goto err; + } + + /* DO read spi */ + ret = consys_hw_spi_read(op->op_data[0], op->op_data[1], &data); + if (data_pt) + *(data_pt) = data; +err: + osal_unlock_sleepable_lock(&g_conninfra_ctx.core_lock); + return ret; +} + +static int opfunc_rfspi_write(struct msg_op_data *op) +{ + int ret = 0; + + ret = osal_lock_sleepable_lock(&g_conninfra_ctx.core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return CONNINFRA_SPI_OP_FAIL; + } + + if (g_conninfra_ctx.infra_drv_status != DRV_STS_POWER_ON) { + pr_err("Connsys didn't power on\n"); + ret = CONNINFRA_SPI_OP_FAIL; + goto err; + } + + if (consys_hw_reg_readable() == 0) { + pr_err("connsys reg not readable\n"); + ret = CONNINFRA_SPI_OP_FAIL; + goto err; + } + + /* DO spi write */ + ret = consys_hw_spi_write(op->op_data[0], op->op_data[1], op->op_data[2]); +err: + osal_unlock_sleepable_lock(&g_conninfra_ctx.core_lock); + return ret; +} + +static int opfunc_adie_top_ck_en_on(struct msg_op_data *op) +{ + int ret = 0; + unsigned int type = op->op_data[0]; + + if (type >= CONNDRV_TYPE_MAX) { + pr_err("wrong parameter %d\n", type); + return -EINVAL; + } + + ret = osal_lock_sleepable_lock(&g_conninfra_ctx.core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + ret = -1; + goto err; + } + + if (g_conninfra_ctx.infra_drv_status != DRV_STS_POWER_ON) { + pr_err("Connsys didn't power on\n"); + ret = -2; + goto err; + } + + ret = consys_hw_adie_top_ck_en_on(type); + +err: + osal_unlock_sleepable_lock(&g_conninfra_ctx.core_lock); + return ret; +} + + +static int opfunc_adie_top_ck_en_off(struct msg_op_data *op) +{ + int ret = 0; + unsigned int type = op->op_data[0]; + + if (type >= CONNDRV_TYPE_MAX) { + pr_err("wrong parameter %d\n", type); + return -EINVAL; + } + + ret = osal_lock_sleepable_lock(&g_conninfra_ctx.core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + ret = -1; + goto err; + } + if (g_conninfra_ctx.infra_drv_status != DRV_STS_POWER_ON) { + pr_err("Connsys didn't power on\n"); + ret = -2; + goto err; + } + + ret = consys_hw_adie_top_ck_en_off(type); +err: + osal_unlock_sleepable_lock(&g_conninfra_ctx.core_lock); + return ret; +} + +static int opfunc_spi_clock_switch(struct msg_op_data *op) +{ + int ret = 0; + unsigned int type = op->op_data[0]; + + if (type >= CONNSYS_SPI_SPEED_MAX) { + pr_err("wrong parameter %d\n", type); + return -EINVAL; + } + + ret = osal_lock_sleepable_lock(&g_conninfra_ctx.core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + ret = -2; + goto err; + } + if (g_conninfra_ctx.infra_drv_status != DRV_STS_POWER_ON) { + pr_err("Connsys didn't power on\n"); + ret = -2; + goto err; + } + + ret = consys_hw_spi_clock_switch(type); +err: + osal_unlock_sleepable_lock(&g_conninfra_ctx.core_lock); + return ret; +} + +static int opfunc_force_conninfra_wakeup(struct msg_op_data *op) +{ + int ret; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return ret; + } + + /* check if conninfra already on */ + if (g_conninfra_ctx.infra_drv_status != DRV_STS_POWER_ON) { + ret = -1; + goto err; + } + + ret = consys_hw_force_conninfra_wakeup(); + if (ret) + pr_err("force conninfra wakeup fail\n"); + +err: + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return ret; +} + +static int opfunc_force_conninfra_sleep(struct msg_op_data *op) +{ + int ret; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return ret; + } + + /* check if conninfra already on */ + if (g_conninfra_ctx.infra_drv_status != DRV_STS_POWER_ON) { + ret = -1; + goto err; + } + + ret = consys_hw_force_conninfra_sleep(); + if (ret) + pr_err("force conninfra sleep fail\n"); + +err: + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return ret; +} + + +static int opfunc_dump_power_state(struct msg_op_data *op) +{ + int ret; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return ret; + } + + /* check if conninfra already on */ + if (g_conninfra_ctx.infra_drv_status != DRV_STS_POWER_ON) { + ret = -1; + goto err; + } + + ret = consys_hw_dump_power_state(); + if (ret) + pr_err("dump power state fail\n"); + +err: + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return ret; + +} + +static int opfunc_subdrv_pre_reset(struct msg_op_data *op) +{ + int ret, cur_rst_state; + unsigned int drv_type = op->op_data[0]; + struct subsys_drv_inst *drv_inst; + + + /* TODO: should be locked, to avoid cb was reset */ + drv_inst = &g_conninfra_ctx.drv_inst[drv_type]; + if (/*drv_inst->drv_status == DRV_ST_POWER_ON &&*/ + drv_inst->ops_cb.rst_cb.pre_whole_chip_rst) { + + ret = drv_inst->ops_cb.rst_cb.pre_whole_chip_rst(g_conninfra_ctx.trg_drv, g_conninfra_ctx.trg_reason); + if (ret) + pr_err("[%s] fail [%d]\n", __func__, ret); + } + + atomic_add(0x1 << drv_type, &g_conninfra_ctx.rst_state); + cur_rst_state = atomic_read(&g_conninfra_ctx.rst_state); + + pr_info("[%s] rst_state=[%d]\n", drv_thread_name[drv_type], cur_rst_state); + + up(&g_conninfra_ctx.rst_sema); + return 0; +} + +static int opfunc_subdrv_post_reset(struct msg_op_data *op) +{ + int ret; + unsigned int drv_type = op->op_data[0]; + struct subsys_drv_inst *drv_inst; + + /* TODO: should be locked, to avoid cb was reset */ + drv_inst = &g_conninfra_ctx.drv_inst[drv_type]; + if (/*drv_inst->drv_status == DRV_ST_POWER_ON &&*/ + drv_inst->ops_cb.rst_cb.post_whole_chip_rst) { + ret = drv_inst->ops_cb.rst_cb.post_whole_chip_rst(); + if (ret) + pr_warn("[%s] fail [%d]\n", __func__, ret); + } + + atomic_add(0x1 << drv_type, &g_conninfra_ctx.rst_state); + up(&g_conninfra_ctx.rst_sema); + return 0; +} + +/* + * CONNINFRA API + */ +int conninfra_core_power_on(enum consys_drv_type type) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = msg_thread_send_wait_1(&infra_ctx->msg_ctx, + CONNINFRA_OPID_PWR_ON, 0, type); + if (ret) { + pr_err("[%s] fail, ret = %d\n", __func__, ret); + return -1; + } + return 0; +} + +int conninfra_core_power_off(enum consys_drv_type type) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = msg_thread_send_wait_1(&infra_ctx->msg_ctx, + CONNINFRA_OPID_PWR_OFF, 0, type); + if (ret) { + pr_err("[%s] send msg fail, ret = %d\n", __func__, ret); + return -1; + } + return 0; +} + +int conninfra_core_reg_readable(void) +{ + int ret = 0, rst_status; + unsigned long flag; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + + /* check if in reseting, can not read */ + spin_lock_irqsave(&g_conninfra_ctx.rst_lock, flag); + rst_status = g_conninfra_ctx.rst_status; + spin_unlock_irqrestore(&g_conninfra_ctx.rst_lock, flag); + + if (rst_status >= CHIP_RST_RESET && + rst_status < CHIP_RST_POST_CB) + return 0; + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return 0; + } + + if (infra_ctx->infra_drv_status == DRV_STS_POWER_ON) + ret = consys_hw_reg_readable(); + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + + return ret; +} + +int conninfra_core_reg_readable_no_lock(void) +{ + int rst_status; + unsigned long flag; + + /* check if in reseting, can not read */ + spin_lock_irqsave(&g_conninfra_ctx.rst_lock, flag); + rst_status = g_conninfra_ctx.rst_status; + spin_unlock_irqrestore(&g_conninfra_ctx.rst_lock, flag); + + if (rst_status >= CHIP_RST_RESET && + rst_status < CHIP_RST_POST_CB) + return 0; + + return consys_hw_reg_readable(); +} + +int conninfra_core_is_bus_hang(void) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return 0; + } + + if (infra_ctx->infra_drv_status == DRV_STS_POWER_ON) + ret = consys_hw_is_bus_hang(); + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + + return ret; + +} + +int conninfra_core_is_consys_reg(phys_addr_t addr) +{ + return consys_hw_is_connsys_reg(addr); +} + +int conninfra_core_reg_read(unsigned long address, unsigned int *value, unsigned int mask) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return 0; + } + + if (infra_ctx->infra_drv_status == DRV_STS_POWER_ON) { + if (consys_reg_mng_is_host_csr(address)) + ret = consys_reg_mng_reg_read(address, value, mask); + else if (consys_hw_reg_readable()) + ret = consys_reg_mng_reg_read(address, value, mask); + else + pr_info("CR (%lx) is not readable\n", address); + } else + pr_info("CR (%lx) cannot read. conninfra is off\n", address); + + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return ret; +} + +int conninfra_core_reg_write(unsigned long address, unsigned int value, unsigned int mask) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return 0; + } + + if (infra_ctx->infra_drv_status == DRV_STS_POWER_ON) { + if (consys_reg_mng_is_host_csr(address)) + ret = consys_reg_mng_reg_write(address, value, mask); + else if (consys_hw_reg_readable()) + ret = consys_reg_mng_reg_write(address, value, mask); + else + pr_info("CR (%p) is not readable\n", (void*)address); + } else + pr_info("CR (%p) cannot read. conninfra is off\n", (void*)address); + + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + return ret; + +} + +int conninfra_core_lock_rst(void) +{ + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + int ret = 0; + unsigned long flag; + + spin_lock_irqsave(&infra_ctx->rst_lock, flag); + + ret = infra_ctx->rst_status; + if (infra_ctx->rst_status > CHIP_RST_NONE && + infra_ctx->rst_status < CHIP_RST_DONE) { + /* do nothing */ + } else { + infra_ctx->rst_status = CHIP_RST_START; + } + spin_unlock_irqrestore(&infra_ctx->rst_lock, flag); + + pr_info("[%s] ret=[%d]\n", __func__, ret); + return ret; +} + +int conninfra_core_unlock_rst(void) +{ + unsigned long flag; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + spin_lock_irqsave(&infra_ctx->rst_lock, flag); + infra_ctx->rst_status = CHIP_RST_NONE; + spin_unlock_irqrestore(&infra_ctx->rst_lock, flag); + return 0; +} + +int conninfra_core_trg_chip_rst(enum consys_drv_type drv, char *reason) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + infra_ctx->trg_drv = drv; + snprintf(infra_ctx->trg_reason, CHIP_RST_REASON_MAX_LEN, "%s", reason); + ret = msg_thread_send_1(&infra_ctx->cb_ctx, + CONNINFRA_CB_OPID_CHIP_RST, drv); + if (ret) { + pr_err("send msg fail, ret = %d\n", ret); + return -1; + } + pr_info("trg_reset DONE!\n"); + return 0; +} + +static inline char* conninfra_core_spi_subsys_string(enum sys_spi_subsystem subsystem) +{ + static char* subsys_name[] = { + "SYS_SPI_WF1", + "SYS_SPI_WF", + "SYS_SPI_BT", + "SYS_SPI_FM", + "SYS_SPI_GPS", + "SYS_SPI_TOP", + "SYS_SPI_WF2", + "SYS_SPI_WF3", + "SYS_SPI_2ND_ADIE_WF1", + "SYS_SPI_2ND_ADIE_WF", + "SYS_SPI_2ND_ADIE_BT", + "SYS_SPI_2ND_ADIE_FM", + "SYS_SPI_2ND_ADIE_GPS", + "SYS_SPI_2ND_ADIE_TOP", + "SYS_SPI_2ND_ADIE_WF2", + "SYS_SPI_2ND_ADIE_WF3", + "SYS_SPI_MAX" + }; + return subsys_name[subsystem]; +} + +int conninfra_core_spi_read(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + size_t data_ptr = (size_t)data; + + ret = msg_thread_send_wait_3(&infra_ctx->msg_ctx, CONNINFRA_OPID_RFSPI_READ, 0, + subsystem, addr, data_ptr); + if (ret) { + pr_err("failed (ret = %d). subsystem=%s addr=%x\n", + ret, conninfra_core_spi_subsys_string(subsystem), addr); + return CONNINFRA_SPI_OP_FAIL; + } + return 0; +} + +int conninfra_core_spi_write(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data) +{ + int ret; + ret = msg_thread_send_wait_3(&(g_conninfra_ctx.msg_ctx), CONNINFRA_OPID_RFSPI_WRITE, 0, + subsystem, addr, data); + if (ret) { + pr_err("failed (ret = %d). subsystem=%s addr=0x%x data=%d\n", + ret, conninfra_core_spi_subsys_string(subsystem), addr, data); + return CONNINFRA_SPI_OP_FAIL; + } + return 0; +} + +int conninfra_core_adie_top_ck_en_on(enum consys_drv_type type) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = msg_thread_send_wait_1(&infra_ctx->msg_ctx, + CONNINFRA_OPID_ADIE_TOP_CK_EN_ON, 0, type); + if (ret) { + pr_err("fail, ret = %d\n", ret); + return -1; + } + return 0; +} + +int conninfra_core_adie_top_ck_en_off(enum consys_drv_type type) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = msg_thread_send_wait_1(&infra_ctx->msg_ctx, + CONNINFRA_OPID_ADIE_TOP_CK_EN_OFF, 0, type); + if (ret) { + pr_err("fail, ret = %d\n", ret); + return -1; + } + return 0; +} + +int conninfra_core_force_conninfra_wakeup(void) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + /* if in conninfra_cored thread */ + if (current == infra_ctx->msg_ctx.thread.pThread) + return opfunc_force_conninfra_wakeup(NULL); + + ret = msg_thread_send_wait(&infra_ctx->msg_ctx, + CONNINFRA_OPID_FORCE_CONNINFRA_WAKUP, 0); + if (ret) { + pr_err("fail, ret = %d\n", ret); + return -1; + } + return 0; +} + +int conninfra_core_force_conninfra_sleep(void) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + /* if in conninfra_cored thread */ + if (current == infra_ctx->msg_ctx.thread.pThread) + return opfunc_force_conninfra_sleep(NULL); + + ret = msg_thread_send_wait(&infra_ctx->msg_ctx, + CONNINFRA_OPID_FORCE_CONNINFRA_SLEEP, 0); + if (ret) { + pr_err("fail, ret = %d\n", ret); + return -1; + } + return 0; +} + +int conninfra_core_spi_clock_switch(enum connsys_spi_speed_type type) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = msg_thread_send_wait_1(&infra_ctx->msg_ctx, + CONNINFRA_OPID_SPI_CLOCK_SWITCH, 0, type); + if (ret) { + pr_err("fail, ret = %d\n", ret); + return -1; + } + return 0; +} + +int conninfra_core_subsys_ops_reg(enum consys_drv_type type, + struct sub_drv_ops_cb *cb) +{ + unsigned long flag; + struct subsys_drv_inst *drv_inst; + int ret = 0; + + spin_lock_irqsave(&g_conninfra_ctx.infra_lock, flag); + drv_inst = &g_conninfra_ctx.drv_inst[type]; + memcpy(&g_conninfra_ctx.drv_inst[type].ops_cb, cb, sizeof(struct sub_drv_ops_cb)); + spin_unlock_irqrestore(&g_conninfra_ctx.infra_lock, flag); + + pr_info("[pre_cal] type=[%s] cb rst=[%p][%p]\n", + drv_name[type], cb->rst_cb.pre_whole_chip_rst, cb->rst_cb.post_whole_chip_rst); + + return ret; +} + +int conninfra_core_subsys_ops_unreg(enum consys_drv_type type) +{ + unsigned long flag; + + spin_lock_irqsave(&g_conninfra_ctx.infra_lock, flag); + memset(&g_conninfra_ctx.drv_inst[type].ops_cb, 0, + sizeof(struct sub_drv_ops_cb)); + spin_unlock_irqrestore(&g_conninfra_ctx.infra_lock, flag); + + return 0; +} + +static void _conninfra_core_update_rst_status(enum chip_rst_status status) +{ + unsigned long flag; + + spin_lock_irqsave(&g_conninfra_ctx.rst_lock, flag); + g_conninfra_ctx.rst_status = status; + spin_unlock_irqrestore(&g_conninfra_ctx.rst_lock, flag); +} + + +int conninfra_core_is_rst_locking(void) +{ + unsigned long flag; + int ret = 0; + + spin_lock_irqsave(&g_conninfra_ctx.rst_lock, flag); + + if (g_conninfra_ctx.rst_status > CHIP_RST_NONE && + g_conninfra_ctx.rst_status < CHIP_RST_POST_CB) + ret = 1; + spin_unlock_irqrestore(&g_conninfra_ctx.rst_lock, flag); + return ret; +} + +int conninfra_core_dump_power_state(void) +{ + int ret = 0; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + ret = msg_thread_send(&infra_ctx->msg_ctx, + CONNINFRA_OPID_DUMP_POWER_STATE); + if (ret) { + pr_err("fail, ret = %d\n", ret); + return -1; + } + + return 0; + +} + +int conninfra_core_pmic_event_cb(unsigned int id, unsigned int event) +{ + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + int ret; + + if (conninfra_core_is_rst_locking()) { + return 0; + } + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail!!\n"); + return 0; + } + + if (infra_ctx->infra_drv_status == DRV_STS_POWER_ON) + consys_hw_pmic_event_cb(id, event); + + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + + return 0; +} + +int conninfra_core_debug_dump(void) +{ + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + int ret = -1; + unsigned int i; + + ret = osal_lock_sleepable_lock(&infra_ctx->core_lock); + if (ret) { + pr_err("core_lock fail, ret=%d\n", ret); + return -1; + } + + msg_thread_dump(&infra_ctx->msg_ctx); + msg_thread_dump(&infra_ctx->cb_ctx); + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + msg_thread_dump(&(infra_ctx->drv_inst[i].msg_ctx)); + } + + osal_unlock_sleepable_lock(&infra_ctx->core_lock); + + return ret; +} + +int conninfra_core_init(void) +{ + int ret = 0, i; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + osal_memset(&g_conninfra_ctx, 0, sizeof(g_conninfra_ctx)); + + reset_chip_rst_trg_data(); + + spin_lock_init(&infra_ctx->infra_lock); + osal_sleepable_lock_init(&infra_ctx->core_lock); + spin_lock_init(&infra_ctx->rst_lock); + + + ret = msg_thread_init(&infra_ctx->msg_ctx, "conninfra_cored", + conninfra_core_opfunc, CONNINFRA_OPID_MAX); + if (ret) { + pr_err("msg_thread init fail(%d)\n", ret); + return -1; + } + + ret = msg_thread_init(&infra_ctx->cb_ctx, "conninfra_cb", + conninfra_core_cb_opfunc, CONNINFRA_CB_OPID_MAX); + if (ret) { + pr_err("callback msg thread init fail(%d)\n", ret); + return -1; + } + + /* init subsys drv state */ + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + ret += msg_thread_init(&infra_ctx->drv_inst[i].msg_ctx, + drv_thread_name[i], infra_subdrv_opfunc, + INFRA_SUBDRV_OPID_MAX); + } + + if (ret) { + pr_err("subsys callback thread init fail.\n"); + return -1; + } + + return ret; +} + +int conninfra_core_deinit(void) +{ + int ret, i; + struct conninfra_ctx *infra_ctx = &g_conninfra_ctx; + + for (i = 0; i < CONNDRV_TYPE_MAX; i++) { + ret = msg_thread_deinit(&infra_ctx->drv_inst[i].msg_ctx); + if (ret) + pr_warn("subdrv [%d] msg_thread deinit fail (%d)\n", + i, ret); + } + + ret = msg_thread_deinit(&infra_ctx->msg_ctx); + if (ret) { + pr_err("msg_thread_deinit fail(%d)\n", ret); + return -1; + } + + osal_sleepable_lock_deinit(&infra_ctx->core_lock); + + return 0; +} + diff --git a/package/mtk/drivers/conninfra/src/core/include/conninfra_core.h b/package/mtk/drivers/conninfra/src/core/include/conninfra_core.h new file mode 100644 index 0000000000..555c8de8a2 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/core/include/conninfra_core.h @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _CONNINFRA_CORE_H_ +#define _CONNINFRA_CORE_H_ + +#include +#include +#include +#include + +#include "osal.h" +#include "msg_thread.h" +#include "conninfra.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define CHIP_RST_REASON_MAX_LEN 128 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +typedef enum _ENUM_DRV_STS_ { + DRV_STS_POWER_OFF = 0, /* initial state */ + DRV_STS_POWER_ON = 1, /* powered on */ + DRV_STS_MAX +} ENUM_DRV_STS, *P_ENUM_DRV_STS; + +enum chip_rst_status { + CHIP_RST_NONE = 0, + CHIP_RST_START = 1, + CHIP_RST_PRE_CB = 2, + CHIP_RST_RESET = 3, + CHIP_RST_POST_CB = 4, + CHIP_RST_DONE = 5 +}; + +struct subsys_drv_inst { + ENUM_DRV_STS drv_status; /* Controlled driver status */ + unsigned int rst_state; + struct sub_drv_ops_cb ops_cb; + struct msg_thread_ctx msg_ctx; +}; + +/* + * state of conninfra + * + */ +struct conninfra_ctx { + ENUM_DRV_STS infra_drv_status; + + struct subsys_drv_inst drv_inst[CONNDRV_TYPE_MAX]; + /*struct spinlock infra_lock;*/ + spinlock_t infra_lock; + + OSAL_SLEEPABLE_LOCK core_lock; + + /* chip reset */ + enum chip_rst_status rst_status; + spinlock_t rst_lock; + + struct semaphore rst_sema; + atomic_t rst_state; + enum consys_drv_type trg_drv; + char trg_reason[CHIP_RST_REASON_MAX_LEN]; + + struct msg_thread_ctx msg_ctx; + struct msg_thread_ctx cb_ctx; + + unsigned int hw_ver; + unsigned int fw_ver; + unsigned int ip_ver; +}; + +//typedef enum _ENUM_CONNINFRA_CORE_OPID_T { +typedef enum { + CONNINFRA_OPID_PWR_ON = 0, + CONNINFRA_OPID_PWR_OFF = 1, + CONNINFRA_OPID_RFSPI_READ = 2, + CONNINFRA_OPID_RFSPI_WRITE = 3, + CONNINFRA_OPID_ADIE_TOP_CK_EN_ON = 4, + CONNINFRA_OPID_ADIE_TOP_CK_EN_OFF = 5, + CONNINFRA_OPID_SPI_CLOCK_SWITCH = 6, + CONNINFRA_OPID_FORCE_CONNINFRA_WAKUP = 7, + CONNINFRA_OPID_FORCE_CONNINFRA_SLEEP = 8, + CONNINFRA_OPID_DUMP_POWER_STATE = 9, + CONNINFRA_OPID_MAX +} conninfra_core_opid; + +/* For the operation which may callback subsys driver */ +typedef enum { + CONNINFRA_CB_OPID_CHIP_RST = 0, + CONNINFRA_CB_OPID_MAX +} conninfra_core_cb_opid; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +extern int conninfra_core_init(void); +extern int conninfra_core_deinit(void); + +int conninfra_core_power_on(enum consys_drv_type type); +int conninfra_core_power_off(enum consys_drv_type type); + +int conninfra_core_lock_rst(void); +int conninfra_core_unlock_rst(void); +int conninfra_core_trg_chip_rst(enum consys_drv_type drv, char *reason); + +int conninfra_core_subsys_ops_reg(enum consys_drv_type type, struct sub_drv_ops_cb *cb); +int conninfra_core_subsys_ops_unreg(enum consys_drv_type type); + +/* reg control */ +/* NOTE: NOT thread-safe + * return value + * 1 : Yes, 0: NO + */ +int conninfra_core_reg_readable(void); +int conninfra_core_reg_readable_no_lock(void); +int conninfra_core_is_bus_hang(void); + +int conninfra_core_is_consys_reg(phys_addr_t addr); +int conninfra_core_reg_read(unsigned long address, unsigned int *value, unsigned int mask); +int conninfra_core_reg_write(unsigned long address, unsigned int value, unsigned int mask); + +int conninfra_core_is_rst_locking(void); + +int conninfra_core_spi_read(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data); +int conninfra_core_spi_write(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data); + +int conninfra_core_adie_top_ck_en_on(enum consys_drv_type type); +int conninfra_core_adie_top_ck_en_off(enum consys_drv_type type); + +int conninfra_core_force_conninfra_wakeup(void); +int conninfra_core_force_conninfra_sleep(void); + +int conninfra_core_spi_clock_switch(enum connsys_spi_speed_type type); + +int conninfra_core_dump_power_state(void); +int conninfra_core_pmic_event_cb(unsigned int, unsigned int); +int conninfra_core_debug_dump(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _CONNINFRA_CORE_H_ */ diff --git a/package/mtk/drivers/conninfra/src/include/conninfra.h b/package/mtk/drivers/conninfra/src/include/conninfra.h new file mode 100644 index 0000000000..b8577bdec3 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/include/conninfra.h @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ + +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _CONNINFRA_H_ +#define _CONNINFRA_H_ + + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define AIDE_NUM_MAX 2 +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +enum consys_drv_type { + CONNDRV_TYPE_BT = 0, + CONNDRV_TYPE_FM = 1, + CONNDRV_TYPE_GPS = 2, + CONNDRV_TYPE_WIFI = 3, + CONNDRV_TYPE_CONNINFRA = 4, + CONNDRV_TYPE_MAX +}; + +/* HW-specific, need sync with FW. DO NOT MODIFY */ +enum sys_spi_subsystem +{ + SYS_SPI_WF1 = 0x00, + SYS_SPI_WF = 0x01, + SYS_SPI_BT = 0x02, + SYS_SPI_FM = 0x03, + SYS_SPI_GPS = 0x04, + SYS_SPI_TOP = 0x05, + SYS_SPI_WF2 = 0x06, + SYS_SPI_WF3 = 0x07, + SYS_SPI_2ND_ADIE_WF1 = 0x10, + SYS_SPI_2ND_ADIE_WF = 0x11, + SYS_SPI_2ND_ADIE_BT = 0x12, + SYS_SPI_2ND_ADIE_FM = 0x13, + SYS_SPI_2ND_ADIE_GPS = 0x14, + SYS_SPI_2ND_ADIE_TOP = 0x15, + SYS_SPI_2ND_ADIE_WF2 = 0x16, + SYS_SPI_2ND_ADIE_WF3 = 0x17, + SYS_SPI_MAX +}; + +enum connsys_spi_speed_type { + CONNSYS_SPI_SPEED_26M, + CONNSYS_SPI_SPEED_64M, + CONNSYS_SPI_SPEED_MAX +}; + +/* Conninfra driver allocate EMI for FW and WFDAM + * (FW includes: BT, WIFI and their MCU) + * +-----------+ + + * | | | + * | FW | | + * | | | + * +-----------+ v + * | | + * | | FW_WFDMA + * | | ^ + * | WFDMA | | + * | | | + * | | | + * +-----------+ + + * + * MCIF region is provided by MD + * +-----------+ + * | | + * | | + * | MCIF | + * | | + * +-----------+ + */ +enum connsys_emi_type +{ + CONNSYS_EMI_FW = 0, + CONNSYS_EMI_MAX, +}; + +#define CONNINFRA_SPI_OP_FAIL 0x1 + +#define CONNINFRA_CB_RET_CAL_PASS_POWER_OFF 0x0 +#define CONNINFRA_CB_RET_CAL_PASS_POWER_ON 0x2 +#define CONNINFRA_CB_RET_CAL_FAIL_POWER_OFF 0x1 +#define CONNINFRA_CB_RET_CAL_FAIL_POWER_ON 0x3 + +#define CONNINFRA_BUS_CLOCK_WPLL 0x1 +#define CONNINFRA_BUS_CLOCK_ALL (CONNINFRA_BUS_CLOCK_WPLL) + +/* bus hang error define */ +#define CONNINFRA_INFRA_BUS_HANG 0x1 +#define CONNINFRA_AP2CONN_RX_SLP_PROT_ERR 0x2 +#define CONNINFRA_AP2CONN_TX_SLP_PROT_ERR 0x4 +#define CONNINFRA_AP2CONN_CLK_ERR 0x8 +#define CONNINFRA_INFRA_BUS_HANG_IRQ 0x10 + +#define CONNINFRA_ERR_RST_ONGOING -0x7788 +#define CONNINFRA_ERR_WAKEUP_FAIL -0x5566 +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/* SPI clock switch */ +int conninfra_spi_clock_switch(enum connsys_spi_speed_type type); + +/* A-die top_ck_en control, only for MT6885 */ +int conninfra_adie_top_ck_en_on(enum consys_drv_type type); +int conninfra_adie_top_ck_en_off(enum consys_drv_type type); + +/* RFSPI */ +int conninfra_spi_read(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data); +int conninfra_spi_write(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data); + +/* EMI */ +void conninfra_get_emi_phy_addr(enum connsys_emi_type type, phys_addr_t* base, unsigned int *size); + +/* power on/off */ +int conninfra_pwr_on(enum consys_drv_type drv_type); +int conninfra_pwr_off(enum consys_drv_type drv_type); + +/* To setup config relative data, ex: debug flag */ +void conninfra_config_setup(void); + +/* + * 0 : NO hang + * > 0 : HANG!! + * CONNINFRA_ERR_RST_ONGOING: whole chip reset is ongoing + */ +int conninfra_is_bus_hang(void); + +/* chip reset +* return: +* <0: error +* =0: triggered +* =1: ongoing +*/ +int conninfra_trigger_whole_chip_rst(enum consys_drv_type drv, char *reason); + +int conninfra_debug_dump(void); + +struct whole_chip_rst_cb { + int (*pre_whole_chip_rst)(enum consys_drv_type drv, char *reason); + int (*post_whole_chip_rst)(void); +}; + +/* driver state query */ + +/* VCN control */ + +/* Thermal */ + +/* Config */ + +/* semaphore */ + +/* calibration */ + +struct sub_drv_ops_cb { + /* chip reset */ + struct whole_chip_rst_cb rst_cb; +}; + +int conninfra_sub_drv_ops_register(enum consys_drv_type drv_type, struct sub_drv_ops_cb *cb); +int conninfra_sub_drv_ops_unregister(enum consys_drv_type drv_type); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _CONNINFRA_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/consys_hw.c b/package/mtk/drivers/conninfra/src/platform/consys_hw.c new file mode 100644 index 0000000000..7f8e02e223 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/consys_hw.c @@ -0,0 +1,663 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + + +#include +#include +#include + +#include "osal.h" +#include "consys_hw.h" +#include "emi_mng.h" +#include "pmic_mng.h" +#include "consys_reg_mng.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +static int mtk_conninfra_probe(struct platform_device *pdev); +static int mtk_conninfra_remove(struct platform_device *pdev); +static int mtk_conninfra_suspend(struct platform_device *pdev, pm_message_t state); +static int mtk_conninfra_resume(struct platform_device *pdev); + +static int consys_hw_init(struct platform_device *pdev); +static int consys_hw_deinit(void); +static int _consys_hw_conninfra_wakeup(void); +static int _consys_hw_conninfra_sleep(void); + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +extern const struct of_device_id apconninfra_of_ids[]; + +static struct platform_driver mtk_conninfra_dev_drv = { + .probe = mtk_conninfra_probe, + .remove = mtk_conninfra_remove, + .suspend = mtk_conninfra_suspend, + .resume = mtk_conninfra_resume, + .driver = { + .name = "mtk_conninfra", + .owner = THIS_MODULE, + .of_match_table = apconninfra_of_ids, + }, +}; + + +struct consys_hw_env conn_hw_env[AIDE_NUM_MAX]; + +const struct consys_hw_ops_struct *consys_hw_ops; +struct platform_device *g_pdev; + +int g_conninfra_wakeup_ref_cnt; + +struct work_struct ap_resume_work; + +struct conninfra_dev_cb *g_conninfra_dev_cb; +const struct conninfra_plat_data *g_conninfra_plat_data = NULL; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +struct platform_device *get_consys_device(void) +{ + return g_pdev; +} + +int consys_hw_get_clock_schematic(void) +{ + if (consys_hw_ops->consys_plt_co_clock_type) + return consys_hw_ops->consys_plt_co_clock_type(); + else + pr_err("consys_hw_ops->consys_co_clock_type not supported\n"); + + return -1; +} + +unsigned int consys_hw_chipid_get(void) +{ + if (g_conninfra_plat_data && g_conninfra_plat_data->chip_id) + return g_conninfra_plat_data->chip_id; + else if (consys_hw_ops->consys_plt_soc_chipid_get) + return consys_hw_ops->consys_plt_soc_chipid_get(); + else + pr_err("consys_plt_soc_chipid_get not supported\n"); + + return 0; +} + +unsigned int consys_hw_get_hw_ver(void) +{ + if (consys_hw_ops->consys_plt_get_hw_ver) + return consys_hw_ops->consys_plt_get_hw_ver(); + return 0; +} + + +int consys_hw_reg_readable(void) +{ + return consys_reg_mng_reg_readable(); +} + +int consys_hw_is_connsys_reg(phys_addr_t addr) +{ + return consys_reg_mng_is_connsys_reg(addr); +} + +int consys_hw_is_bus_hang(void) +{ + return consys_reg_mng_is_bus_hang(); +} + +int consys_hw_dump_bus_status(void) +{ + return consys_reg_mng_dump_bus_status(); +} + +int consys_hw_dump_cpupcr(enum conn_dump_cpupcr_type dump_type, int times, unsigned long interval_us) +{ + return consys_reg_mng_dump_cpupcr(dump_type, times, interval_us); +} + +int consys_hw_pwr_on(unsigned int curr_status, unsigned int on_radio) +{ + //unsigned int next_status = (curr_status | (0x1 << on_radio)); + + /* first power on */ + if (curr_status == 0) { + /* POS PART 0: + * Set PMIC to turn on the power that AFE WBG circuit in D-die, + * OSC or crystal component, and A-die need. + */ + if (consys_hw_ops->consys_plt_xtal_ctrl_fast_mode) + consys_hw_ops->consys_plt_xtal_ctrl_fast_mode(); + + if (consys_hw_ops->consys_plt_connsys_sw_reset_ctrl) + consys_hw_ops->consys_plt_connsys_sw_reset_ctrl(false); + + /* POS PART 1: + * 1. Pinmux setting + * 2. Turn on MTCMOS + * 3. Enable AHB bus + */ + if (consys_hw_ops->consys_plt_set_if_pinmux) + consys_hw_ops->consys_plt_set_if_pinmux(true); + + udelay(500); + + if (consys_hw_ops->consys_plt_tx_rx_bus_slp_prot_ctrl) + consys_hw_ops->consys_plt_tx_rx_bus_slp_prot_ctrl(true); + + if (consys_hw_ops->consys_plt_polling_consys_chipid) + consys_hw_ops->consys_plt_polling_consys_chipid(); + + /* POS PART 2: + * 1. Set connsys EMI mapping + * 2. d_die_cfg + * 3. spi_master_cfg + * 4. a_die_cfg + * 5. afe_wbg_cal + * 6. patch default value + * 7. CONN_INFRA low power setting (srcclken wait time, mtcmos HW ctl...) + */ + if (consys_hw_ops->consys_plt_bus_clock_ctrl) + consys_hw_ops->consys_plt_bus_clock_ctrl(on_radio, CONNINFRA_BUS_CLOCK_ALL); + + emi_mng_set_remapping_reg(); + emi_mng_set_region_protection(); + + if (consys_hw_ops->consys_plt_d_die_cfg) + consys_hw_ops->consys_plt_d_die_cfg(); + + if (consys_hw_ops->consys_plt_conninfra_sysram_hw_ctrl) + consys_hw_ops->consys_plt_conninfra_sysram_hw_ctrl(); + + if (consys_hw_ops->consys_plt_spi_master_cfg) + consys_hw_ops->consys_plt_spi_master_cfg(); + +#ifndef CONFIG_FPGA_EARLY_PORTING + if (consys_hw_ops->consys_plt_adie_type_check) + consys_hw_ops->consys_plt_adie_type_check(); + + if (consys_hw_ops->consys_plt_a_die_cfg) + consys_hw_ops->consys_plt_a_die_cfg(); +#endif + + if (consys_hw_ops->consys_plt_afe_wbg_cal) + consys_hw_ops->consys_plt_afe_wbg_cal(); + + if (consys_hw_ops->consys_plt_subsys_pll_initial) + consys_hw_ops->consys_plt_subsys_pll_initial(); + + if (consys_hw_ops->consys_plt_osc_legacy_mode) + consys_hw_ops->consys_plt_osc_legacy_mode(); + +#ifndef CONFIG_FPGA_EARLY_PORTING + if (consys_hw_ops->consys_plt_top_pwr_ctrl) + consys_hw_ops->consys_plt_top_pwr_ctrl(); +#endif + + if (consys_hw_ops->consys_plt_conn_infra_bus_timeout) + consys_hw_ops->consys_plt_conn_infra_bus_timeout(); + + if (consys_hw_ops->consys_plt_clkgen_wpll_hw_ctrl) + consys_hw_ops->consys_plt_clkgen_wpll_hw_ctrl(); + + /* POS PART 3: + * 1. A-die low power setting + * 2. bgfsys power on(BT/GPS on) + */ + consys_hw_force_conninfra_wakeup(); +#ifndef CONFIG_FPGA_EARLY_PORTING + consys_hw_adie_top_ck_en_on(on_radio); + //consys_hw_adie_top_ck_en_off(on_radio); +#endif + consys_hw_force_conninfra_sleep(); + }else { + switch (on_radio) { + case CONNDRV_TYPE_WIFI: + /* Power on WFSYS PART 0: + * 1. wake up conn_infra + * 2. turn on MTCMOS power switch of "wfsys_top_on" and "wfsys_top_off" circuit in D-die ("wfsys_top_off" is turned on by "wfsys_top_on" automatically) + * 3. enable AHB bus(WF2conn/conn2WF) + * 4. downlad CONNSYS EMI code + * 5. patch default value + */ + if (consys_hw_ops->consys_plt_conninfra_wf_wakeup) + consys_hw_ops->consys_plt_conninfra_wf_wakeup(); + + if (consys_hw_ops->consys_plt_conn_wmcpu_sw_reset) + consys_hw_ops->consys_plt_conn_wmcpu_sw_reset(true); + + if (consys_hw_ops->consys_plt_wf_bus_slp_prot_ctrl) + consys_hw_ops->consys_plt_wf_bus_slp_prot_ctrl(false); + + if (consys_hw_ops->consys_plt_wfsys_top_on_ctrl) + consys_hw_ops->consys_plt_wfsys_top_on_ctrl(true); + + if (consys_hw_ops->consys_plt_wfsys_bus_slp_prot_check) + consys_hw_ops->consys_plt_wfsys_bus_slp_prot_check(true); + + if (consys_hw_ops->consys_plt_wfsys_bus_timeout_ctrl) + consys_hw_ops->consys_plt_wfsys_bus_timeout_ctrl(); + + if (consys_hw_ops->consys_plt_conn_wmcpu_sw_reset) + consys_hw_ops->consys_plt_conn_wmcpu_sw_reset(false); + +#ifndef CONFIG_FPGA_EARLY_PORTING + if (consys_hw_ops->consys_plt_conn_wmcpu_idle_loop_check) + consys_hw_ops->consys_plt_conn_wmcpu_idle_loop_check(); + + if (consys_hw_ops->consys_plt_adie_type_cfg) + consys_hw_ops->consys_plt_adie_type_cfg(); +#endif + /* No sleep requiremenct for rebb AP */ +#if 0 + if (consys_hw_ops->consys_plt_conninfra_wf_sleep) + consys_hw_ops->consys_plt_conninfra_wf_sleep(); +#endif + break; + + default: + pr_err("Not support type now (on_radio = %d)\n", on_radio); + break; + } + } + + return 0; +} + +int consys_hw_pwr_off(unsigned int curr_status, unsigned int off_radio) +{ + //int ret = 0; + unsigned int next_status = curr_status & ~(0x1 << off_radio); + + if (next_status == 0) { + pr_info("Last pwoer off: %d\n", off_radio); + + /* Power off CONNSYS PART 0: + * 1. A-die low power setting + */ + consys_hw_force_conninfra_wakeup(); +#ifndef CONFIG_FPGA_EARLY_PORTING + //consys_hw_adie_top_ck_en_off(off_radio); +#endif + consys_hw_force_conninfra_sleep(); + + /* Power off CONNSYS PART 1: + * 1. disable AXI bus + * 2. turn off MTCMOS power switch of "conn_top_on" and "conn_top_off" circuit in D-die + */ + if (consys_hw_ops->consys_plt_tx_rx_bus_slp_prot_ctrl) + consys_hw_ops->consys_plt_tx_rx_bus_slp_prot_ctrl(false); + + if (consys_hw_ops->consys_plt_connsys_sw_reset_ctrl) + consys_hw_ops->consys_plt_connsys_sw_reset_ctrl(true); + + udelay(1); + } else { + switch (off_radio) { + case CONNDRV_TYPE_WIFI: + /* Power off WFSYS PART 1: + * 1. disable AXI bus(wf2conn/conn2wf) + * 2. turn off MTCMOS power switch of "wf_top_on" and "wf_top_off" circuit in D-die ("wf_top_off" is turned off by "wf_top_on" automatically) + */ + if (consys_hw_ops->consys_plt_conninfra_wf_wakeup) + consys_hw_ops->consys_plt_conninfra_wf_wakeup(); + + if (consys_hw_ops->consys_plt_wf_bus_slp_prot_ctrl) + consys_hw_ops->consys_plt_wf_bus_slp_prot_ctrl(true); + + if (consys_hw_ops->consys_plt_wfsys_bus_slp_prot_check) + consys_hw_ops->consys_plt_wfsys_bus_slp_prot_check(false); + + if (consys_hw_ops->consys_plt_wpll_ctrl) + consys_hw_ops->consys_plt_wpll_ctrl(false); + + if (consys_hw_ops->consys_plt_wfsys_top_on_ctrl) + consys_hw_ops->consys_plt_wfsys_top_on_ctrl(false); + + if (consys_hw_ops->consys_plt_wpll_ctrl) + consys_hw_ops->consys_plt_wpll_ctrl(true); + + consys_hw_adie_top_ck_en_off(off_radio); + + if (consys_hw_ops->consys_plt_conninfra_wf_req_clr) + consys_hw_ops->consys_plt_conninfra_wf_req_clr(); + + if (consys_hw_ops->consys_plt_conninfra_wf_sleep) + consys_hw_ops->consys_plt_conninfra_wf_sleep(); + break; + + default: + consys_hw_force_conninfra_wakeup(); + consys_hw_adie_top_ck_en_off(off_radio); + consys_hw_force_conninfra_sleep(); + break; + } + } + + return 0; +} + +int consys_hw_wifi_power_ctl(unsigned int enable) +{ + return pmic_mng_wifi_power_ctrl(enable); +} + +int consys_hw_bt_power_ctl(unsigned int enable) +{ + return pmic_mng_bt_power_ctrl(enable); +} + +int consys_hw_gps_power_ctl(unsigned int enable) +{ + return pmic_mng_gps_power_ctrl(enable); +} + +int consys_hw_fm_power_ctl(unsigned int enable) +{ + return pmic_mng_fm_power_ctrl(enable); +} + +int consys_hw_dump_power_state(void) +{ + if (consys_hw_ops && consys_hw_ops->consys_plt_power_state) + consys_hw_ops->consys_plt_power_state(); + return 0; +} + +int consys_hw_spi_read(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data) +{ + if (consys_hw_ops->consys_plt_spi_read) + return consys_hw_ops->consys_plt_spi_read(subsystem, addr, data); + return -1; +} + +int consys_hw_spi_write(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data) +{ + if (consys_hw_ops->consys_plt_spi_write) + return consys_hw_ops->consys_plt_spi_write(subsystem, addr, data); + return -1; +} + +int consys_hw_adie_top_ck_en_on(enum consys_drv_type type) +{ + if (consys_hw_ops->consys_plt_adie_top_ck_en_on_off_ctrl) + return consys_hw_ops->consys_plt_adie_top_ck_en_on_off_ctrl(type, 1); + return -1; +} + +int consys_hw_adie_top_ck_en_off(enum consys_drv_type type) +{ + if (consys_hw_ops->consys_plt_adie_top_ck_en_on_off_ctrl) + return consys_hw_ops->consys_plt_adie_top_ck_en_on_off_ctrl(type, 0); + return -1; +} + + +static int _consys_hw_conninfra_wakeup(void) +{ + int ref = g_conninfra_wakeup_ref_cnt; + bool wakeup = false, ret; + + if (consys_hw_ops->consys_plt_conninfra_wakeup) { + if (g_conninfra_wakeup_ref_cnt == 0) { + ret = consys_hw_ops->consys_plt_conninfra_wakeup(); + if (ret) { + pr_err("wakeup fail!! ret=[%d]\n", ret); + return ret; + } + wakeup = true; + } + + g_conninfra_wakeup_ref_cnt++; + } + + pr_info("conninfra_wakeup refcnt=[%d]->[%d] %s\n", + ref, g_conninfra_wakeup_ref_cnt, (wakeup ? "wakeup!!" : "")); + + return 0; +} + +static int _consys_hw_conninfra_sleep(void) +{ + int ref = g_conninfra_wakeup_ref_cnt; + bool sleep = false; + + if (consys_hw_ops->consys_plt_conninfra_sleep && + --g_conninfra_wakeup_ref_cnt == 0) { + sleep = true; + consys_hw_ops->consys_plt_conninfra_sleep(); + } + + if (g_conninfra_wakeup_ref_cnt < 0) + g_conninfra_wakeup_ref_cnt = 0; + + pr_info("conninfra_sleep refcnt=[%d]->[%d] %s\n", + ref, g_conninfra_wakeup_ref_cnt, (sleep ? "sleep!!" : "")); + + return 0; +} + +int consys_hw_force_conninfra_wakeup(void) +{ + return _consys_hw_conninfra_wakeup(); +} + +int consys_hw_force_conninfra_sleep(void) +{ + return _consys_hw_conninfra_sleep(); +} + +int consys_hw_spi_clock_switch(enum connsys_spi_speed_type type) +{ + if (consys_hw_ops->consys_plt_spi_clock_switch) + return consys_hw_ops->consys_plt_spi_clock_switch(type); + return -1; +} + +int consys_hw_pmic_event_cb(unsigned int id, unsigned int event) +{ + pmic_mng_event_cb(id, event); + return 0; +} + +int mtk_conninfra_probe(struct platform_device *pdev) +{ + int ret = -1; + + if (pdev) + g_pdev = pdev; + else { + pr_err("pdev is NULL\n"); + return -1; + } + + g_conninfra_plat_data = (const struct conninfra_plat_data*)of_device_get_match_data(&pdev->dev); + if (g_conninfra_plat_data == NULL) { + pr_err("Get platform data fail.\n"); + return -2; + } + + if (consys_hw_ops == NULL) + consys_hw_ops = (const struct consys_hw_ops_struct*)g_conninfra_plat_data->hw_ops; + if (consys_hw_ops == NULL) { + pr_err("Get HW op fail\n"); + return -3; + } + + /* Read device node */ + if (consys_reg_mng_init(pdev, g_conninfra_plat_data) != 0) { + pr_err("consys_plt_read_reg_from_dts fail\n"); + return -4; + } + + if (consys_hw_ops->consys_plt_clk_get_from_dts) { + if (consys_hw_ops->consys_plt_clk_get_from_dts(pdev) != 0) { + pr_err("consys_plt_clk_get_from_dts fail\n"); + return -5; + } + } + + /* HW operation init */ + if (consys_hw_init(pdev) != 0) { + pr_err("consys_hw_init fail\n"); + return -6; + } + + /* emi mng init */ + ret = emi_mng_init(pdev, g_conninfra_plat_data); + if (ret) { + pr_err("emi_mng init fail, %d\n", ret); + return -7; + } + + ret = pmic_mng_init(pdev, g_conninfra_dev_cb, g_conninfra_plat_data); + if (ret) { + pr_err("pmic_mng init fail, %d\n", ret); + return -8; + } + + return ret; +} + +int mtk_conninfra_remove(struct platform_device *pdev) +{ + int ret; + + ret = pmic_mng_deinit(); + pr_info("pmic_mng_deinit ret=%d\n", ret); + + ret = emi_mng_deinit(); + pr_info("emi_mng_deinit ret=%d\n", ret); + + if (consys_hw_ops->consys_plt_clk_detach) + consys_hw_ops->consys_plt_clk_detach(); + else + pr_err("consys_plt_clk_detach is null\n"); + + ret = consys_reg_mng_deinit(); + pr_info("consys_reg_mng_deinit ret=%d\n", ret); + + ret = consys_hw_deinit(); + pr_info("consys_hw_deinit ret=%d\n", ret); + + if (g_pdev) + g_pdev = NULL; + + return 0; +} + +int mtk_conninfra_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +int mtk_conninfra_resume(struct platform_device *pdev) +{ + /* suspend callback is in atomic context, use schedule work to execute STEP */ + + schedule_work(&ap_resume_work); + return 0; +} + +static void consys_hw_ap_resume_handler(struct work_struct *work) +{ + if (g_conninfra_dev_cb && g_conninfra_dev_cb->conninfra_resume_cb) + (*g_conninfra_dev_cb->conninfra_resume_cb)(); +} + +int consys_hw_init(struct platform_device *pdev) +{ + int iRet = 0; + + if (consys_hw_ops->consys_plt_hw_init) + iRet = consys_hw_ops->consys_plt_hw_init(); + + return iRet; +} + +int consys_hw_deinit(void) +{ + return 0; +} + +int mtk_conninfra_drv_init(struct conninfra_dev_cb *dev_cb) +{ + int iRet = 0; + + g_conninfra_dev_cb = dev_cb; + + pr_info("Before platform_driver_register\n"); + + iRet = platform_driver_register(&mtk_conninfra_dev_drv); + if (iRet) + pr_err("Conninfra platform driver registered failed(%d)\n", iRet); + + pr_info("After platform_driver_register\n"); + + INIT_WORK(&ap_resume_work, consys_hw_ap_resume_handler); + + return iRet; +} + +int mtk_conninfra_drv_deinit(void) +{ + platform_driver_unregister(&mtk_conninfra_dev_drv); + g_conninfra_dev_cb = NULL; + return 0; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/consys_hw_plat_data.c b/package/mtk/drivers/conninfra/src/platform/consys_hw_plat_data.c new file mode 100644 index 0000000000..1841b535d1 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/consys_hw_plat_data.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. + */ +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ +#include + +#include "consys_hw.h" + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/* Platform data */ +#ifdef CONNINFRA_APSOC_MT7986 +extern struct conninfra_plat_data mt7986_plat_data; +const struct of_device_id apconninfra_of_ids[] = { + { + .compatible = "mediatek,mt7986-consys", + .data = (void*)&mt7986_plat_data, + }, + {} +}; +#endif + +#ifdef CONNINFRA_APSOC_MT7981 +extern struct conninfra_plat_data mt7981_plat_data; +const struct of_device_id apconninfra_of_ids[] = { + { + .compatible = "mediatek,mt7981-consys", + .data = (void*)&mt7981_plat_data, + }, + {} +}; +#endif diff --git a/package/mtk/drivers/conninfra/src/platform/consys_reg_mng.c b/package/mtk/drivers/conninfra/src/platform/consys_reg_mng.c new file mode 100644 index 0000000000..e92a99d7c1 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/consys_reg_mng.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include "consys_hw.h" +#include "consys_reg_mng.h" +#include "consys_reg_util.h" + +const struct consys_reg_mng_ops* g_consys_reg_ops = NULL; + +int consys_reg_mng_reg_readable(void) +{ + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_check_reable) + return g_consys_reg_ops->consys_reg_mng_check_reable(); + + return -1; +} + +int consys_reg_mng_is_connsys_reg(phys_addr_t addr) +{ + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_is_consys_reg) + return g_consys_reg_ops->consys_reg_mng_is_consys_reg(addr); + + return -1; +} + + +int consys_reg_mng_is_bus_hang(void) +{ + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_is_bus_hang) + return g_consys_reg_ops->consys_reg_mng_is_bus_hang(); + + return -1; +} + +int consys_reg_mng_dump_bus_status(void) +{ + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_dump_bus_status) + return g_consys_reg_ops->consys_reg_mng_dump_bus_status(); + + return -1; +} + +int consys_reg_mng_dump_conninfra_status(void) +{ + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_dump_conninfra_status) + return g_consys_reg_ops->consys_reg_mng_dump_conninfra_status(); + + return -1; +} + +int consys_reg_mng_dump_cpupcr(enum conn_dump_cpupcr_type dump_type, int times, unsigned long interval_us) +{ + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_dump_cpupcr) + return g_consys_reg_ops->consys_reg_mng_dump_cpupcr(dump_type, times, interval_us); + + return -1; +} + +int consys_reg_mng_init(struct platform_device *pdev, const struct conninfra_plat_data* plat_data) +{ + int ret = 0; + if (g_consys_reg_ops == NULL) + g_consys_reg_ops = (const struct consys_reg_mng_ops*)plat_data->reg_ops; + + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_init) + ret = g_consys_reg_ops->consys_reg_mng_init(pdev); + else + ret = EFAULT; + + return ret; +} + +int consys_reg_mng_deinit(void) +{ + if (g_consys_reg_ops&& + g_consys_reg_ops->consys_reg_mng_deinit) + g_consys_reg_ops->consys_reg_mng_deinit(); + + return 0; +} + +int consys_reg_mng_reg_read(unsigned long addr, unsigned int *value, unsigned int mask) +{ + void __iomem *vir_addr = NULL; + + vir_addr = ioremap_nocache(addr, 0x100); + if (!vir_addr) { + pr_err("ioremap fail\n"); + return -1; + } + + *value = (unsigned int)CONSYS_REG_READ(vir_addr) & mask; + + pr_info("[%x] mask=[%x]\n", *value, mask); + + iounmap(vir_addr); + return 0; +} + +int consys_reg_mng_reg_write(unsigned long addr, unsigned int value, unsigned int mask) +{ + void __iomem *vir_addr = NULL; + + vir_addr = ioremap_nocache(addr, 0x100); + if (!vir_addr) { + pr_err("ioremap fail\n"); + return -1; + } + + CONSYS_REG_WRITE_MASK(vir_addr, value, mask); + + iounmap(vir_addr); + return 0; +} + + +int consys_reg_mng_is_host_csr(unsigned long addr) +{ + if (g_consys_reg_ops && + g_consys_reg_ops->consys_reg_mng_is_host_csr) + return g_consys_reg_ops->consys_reg_mng_is_host_csr(addr); + + return -1; +} diff --git a/package/mtk/drivers/conninfra/src/platform/emi_mng.c b/package/mtk/drivers/conninfra/src/platform/emi_mng.c new file mode 100644 index 0000000000..15a9028f1f --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/emi_mng.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include +#include +#include +#include +#include "osal.h" + +#include "consys_hw.h" +#include "emi_mng.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +unsigned long long gConEmiSize = 0; +phys_addr_t gConEmiPhyBase = 0x0; + +const struct consys_platform_emi_ops* consys_platform_emi_ops = NULL; + +struct consys_emi_addr_info connsys_emi_addr_info = { + .emi_ap_phy_base = 0, + .emi_ap_phy_size = 0, + .fw_emi_size = 0, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +int emi_mng_set_region_protection(void) +{ + if (consys_platform_emi_ops && + consys_platform_emi_ops->consys_ic_emi_set_region_protection) + return consys_platform_emi_ops->consys_ic_emi_set_region_protection(); + + return -1; +} + +int emi_mng_set_remapping_reg(void) +{ + if (consys_platform_emi_ops && + consys_platform_emi_ops->consys_ic_emi_set_remapping_reg) + return consys_platform_emi_ops->consys_ic_emi_set_remapping_reg(); + + return -1; +} + +struct consys_emi_addr_info* emi_mng_get_phy_addr(void) +{ + return &connsys_emi_addr_info; +} + +int emi_mng_init(struct platform_device *pdev, const struct conninfra_plat_data* plat_data) +{ + unsigned int fw_emi_size = 0; + +#ifdef CONFIG_CONNINFRA_EMI_SUPPORT + struct device_node *np; + struct reserved_mem *rmem; + + np = of_parse_phandle(pdev->dev.of_node, "memory-region", 0); + if (!np) { + pr_info("[%s] memory region not found.\n", __func__); + return -1; + } + + rmem = of_reserved_mem_lookup(np); + if (!rmem) { + pr_info("[%s] no memory-region\n", __func__); + return -1; + } else { + gConEmiPhyBase = rmem->base; + gConEmiSize = rmem->size; + } +#else + pr_info("Conninfra not support EMI reservation for %04x\n", plat_data->chip_id); +#endif /* CONFIG_CONNINFRA_EMI_SUPPORT */ + + if (consys_platform_emi_ops == NULL) { + consys_platform_emi_ops = (const struct consys_platform_emi_ops*)plat_data->platform_emi_ops; + } + + if (consys_platform_emi_ops && consys_platform_emi_ops->consys_ic_emi_get_fw_emi_size) + fw_emi_size = consys_platform_emi_ops->consys_ic_emi_get_fw_emi_size(); + + pr_info("[emi_mng_init] gConEmiPhyBase = [0x%llx] size = [0x%llx] fw size = [0x%x] ops=[%p]\n", + gConEmiPhyBase, gConEmiSize, fw_emi_size, consys_platform_emi_ops); + + if (gConEmiPhyBase) { + connsys_emi_addr_info.emi_ap_phy_base = gConEmiPhyBase; + connsys_emi_addr_info.emi_ap_phy_size = gConEmiSize; + connsys_emi_addr_info.fw_emi_size = fw_emi_size; + } else { + pr_err("consys emi memory address gConEmiPhyBase invalid\n"); + } + + return 0; +} + +int emi_mng_deinit(void) +{ + return 0; +} diff --git a/package/mtk/drivers/conninfra/src/platform/include/consys_hw.h b/package/mtk/drivers/conninfra/src/platform/include/consys_hw.h new file mode 100644 index 0000000000..ab2ea8839c --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/include/consys_hw.h @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_CONSYS_HW_H_ +#define _PLATFORM_CONSYS_HW_H_ + +#include +#include "conninfra.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define CONN_SEMA_GET_SUCCESS 0 +#define CONN_SEMA_GET_FAIL 1 + +#define CONN_SEMA_TIMEOUT (1*1000) /* 1ms */ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +struct conninfra_dev_cb { + int (*conninfra_suspend_cb) (void); + int (*conninfra_resume_cb) (void); + int (*conninfra_pmic_event_notifier) (unsigned int, unsigned int); +}; + +typedef int(*CONSYS_PLT_HW_INIT)(void); +typedef int(*CONSYS_PLT_XTAL_CTRL_FAST_MODE)(void); +typedef int(*CONSYS_PLT_CONNSYS_SW_RESET_CTRL)(bool bassert); +typedef void(*CONSYS_PLT_SET_IF_PINMUX)(bool enable); +typedef int(*CONSYS_PLT_TX_RX_BUS_SLP_PROT_CTRL)(bool enable); +typedef int(*CONSYS_PLT_POLLING_CONSYS_CHIPID)(void); +typedef int(*CONSYS_PLT_BUS_CLOCK_CTRL)(enum consys_drv_type drv_type, unsigned int bus_clock); +typedef int(*CONSYS_PLT_D_DIE_CFG)(void); +typedef int(*CONSYS_PLT_CONNINFRA_SYSRAM_HW_CTRL)(void); +typedef int(*CONSYS_PLT_SPI_MASTER_CFG)(void); +typedef int(*CONSYS_PLT_A_DIE_CFG)(void); +typedef int(*CONSYS_PLT_AFE_WBG_CAL)(void); +typedef int(*CONSYS_PLT_SUBSYS_PLL_INITIAL)(void); +typedef int(*CONSYS_PLT_OSC_LEGACY_MODE)(void); +typedef int(*CONSYS_PLT_TOP_PWR_CTRL)(void); +typedef int(*CONSYS_PLT_CONN_INFRA_BUS_TIMEOUT)(void); +typedef int(*CONSYS_PLT_CLKGEN_WPLL_HW_CTRL)(void); +typedef int(*CONSYS_PLT_CONNINFRA_TOP_WAKEUP) (void); +typedef int(*CONSYS_PLT_CONNINFRA_TOP_SLEEP) (void); +typedef int(*CONSYS_PLT_ADIE_TOP_CK_EN_ON_OFF_CTRL)(enum consys_drv_type type, unsigned char on); +typedef int(*CONSYS_PLT_CONNINFRA_WF_WAKEUP) (void); +typedef int(*CONSYS_PLT_CONNINFRA_WF_SLEEP) (void); +typedef int(*CONSYS_PLT_CONN_WMCPU_SW_RESET) (bool bassert); +typedef int(*CONSYS_PLT_WF_BUS_SLP_PROT_CTRL)(bool enable); +typedef int(*CONSYS_PLT_WFSYS_TOP_ON_CTRL) (bool enable); +typedef int(*CONSYS_PLT_WFSYS_BUS_SLP_PROT_CHECK)(bool enable); +typedef int(*CONSYS_PLT_WFSYS_BUS_TIMEOUT_CTRL) (void); +typedef int(*CONSYS_PLT_CONN_WMCPU_IDLE_LOOP_CHECK) (void); +typedef int(*CONSYS_PLT_WPLL_CTRL)(bool enable); +typedef int(*CONSYS_PLT_CONNINFRA_WF_REQ_CLR) (void); +typedef int(*CONSYS_PLT_CLK_GET_FROM_DTS) (struct platform_device *pdev); +typedef int(*CONSYS_PLT_CLK_DETACH) (void); +typedef int(*CONSYS_PLT_CO_CLOCK_TYPE) (void); +typedef unsigned int(*CONSYS_PLT_SOC_CHIPID_GET) (void); +typedef unsigned int(*CONSYS_PLT_GET_HW_VER)(void); +typedef int(*CONSYS_PLT_SPI_READ)(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data); +typedef int(*CONSYS_PLT_SPI_WRITE)(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data); +typedef int(*CONSYS_PLT_SPI_CLOCK_SWITCH)(enum connsys_spi_speed_type type); +typedef int(*CONSYS_PLT_POWER_STATE)(void); +typedef int(*CONSYS_PLT_AIDE_TYPE_CHECK)(void); +typedef int(*CONSYS_PLT_AIDE_TYPE_CFG)(void); + +struct consys_hw_ops_struct { + /* HW init */ + CONSYS_PLT_HW_INIT consys_plt_hw_init; + + /* Power on/off CONNSYS PART (by Conn_infra Driver) */ + CONSYS_PLT_XTAL_CTRL_FAST_MODE consys_plt_xtal_ctrl_fast_mode; + CONSYS_PLT_CONNSYS_SW_RESET_CTRL consys_plt_connsys_sw_reset_ctrl; + CONSYS_PLT_SET_IF_PINMUX consys_plt_set_if_pinmux; + CONSYS_PLT_TX_RX_BUS_SLP_PROT_CTRL consys_plt_tx_rx_bus_slp_prot_ctrl; + CONSYS_PLT_POLLING_CONSYS_CHIPID consys_plt_polling_consys_chipid; + CONSYS_PLT_BUS_CLOCK_CTRL consys_plt_bus_clock_ctrl; + CONSYS_PLT_D_DIE_CFG consys_plt_d_die_cfg; + CONSYS_PLT_CONNINFRA_SYSRAM_HW_CTRL consys_plt_conninfra_sysram_hw_ctrl; + CONSYS_PLT_SPI_MASTER_CFG consys_plt_spi_master_cfg; + CONSYS_PLT_A_DIE_CFG consys_plt_a_die_cfg; + CONSYS_PLT_AFE_WBG_CAL consys_plt_afe_wbg_cal; + CONSYS_PLT_SUBSYS_PLL_INITIAL consys_plt_subsys_pll_initial; + CONSYS_PLT_OSC_LEGACY_MODE consys_plt_osc_legacy_mode; + CONSYS_PLT_TOP_PWR_CTRL consys_plt_top_pwr_ctrl; + CONSYS_PLT_CONN_INFRA_BUS_TIMEOUT consys_plt_conn_infra_bus_timeout; + CONSYS_PLT_CLKGEN_WPLL_HW_CTRL consys_plt_clkgen_wpll_hw_ctrl; + CONSYS_PLT_CONNINFRA_TOP_WAKEUP consys_plt_conninfra_wakeup; + CONSYS_PLT_CONNINFRA_TOP_SLEEP consys_plt_conninfra_sleep; + CONSYS_PLT_ADIE_TOP_CK_EN_ON_OFF_CTRL consys_plt_adie_top_ck_en_on_off_ctrl; + CONSYS_PLT_WPLL_CTRL consys_plt_wpll_ctrl; + + /* Power on/off WFSYS PART 0 (by WF Driver) */ + CONSYS_PLT_CONNINFRA_WF_WAKEUP consys_plt_conninfra_wf_wakeup; + CONSYS_PLT_CONNINFRA_WF_SLEEP consys_plt_conninfra_wf_sleep; + CONSYS_PLT_CONN_WMCPU_SW_RESET consys_plt_conn_wmcpu_sw_reset; + CONSYS_PLT_WF_BUS_SLP_PROT_CTRL consys_plt_wf_bus_slp_prot_ctrl; + CONSYS_PLT_WFSYS_TOP_ON_CTRL consys_plt_wfsys_top_on_ctrl; + CONSYS_PLT_WFSYS_BUS_SLP_PROT_CHECK consys_plt_wfsys_bus_slp_prot_check; + CONSYS_PLT_WFSYS_BUS_TIMEOUT_CTRL consys_plt_wfsys_bus_timeout_ctrl; + CONSYS_PLT_CONN_WMCPU_IDLE_LOOP_CHECK consys_plt_conn_wmcpu_idle_loop_check; + CONSYS_PLT_CONNINFRA_WF_REQ_CLR consys_plt_conninfra_wf_req_clr; + + /* load from dts */ + CONSYS_PLT_CLK_GET_FROM_DTS consys_plt_clk_get_from_dts; + CONSYS_PLT_CLK_DETACH consys_plt_clk_detach; + + /* clock */ + CONSYS_PLT_CO_CLOCK_TYPE consys_plt_co_clock_type; + + CONSYS_PLT_SOC_CHIPID_GET consys_plt_soc_chipid_get; + + /* debug */ + CONSYS_PLT_GET_HW_VER consys_plt_get_hw_ver; + + /* For SPI operation */ + CONSYS_PLT_SPI_READ consys_plt_spi_read; + CONSYS_PLT_SPI_WRITE consys_plt_spi_write; + + /* For SPI clock switch */ + CONSYS_PLT_SPI_CLOCK_SWITCH consys_plt_spi_clock_switch; + + /* power state */ + CONSYS_PLT_POWER_STATE consys_plt_power_state; + + /* others */ + CONSYS_PLT_AIDE_TYPE_CHECK consys_plt_adie_type_check; + CONSYS_PLT_AIDE_TYPE_CFG consys_plt_adie_type_cfg; +}; + +struct consys_hw_env { + bool valid; + unsigned int adie_hw_version; + unsigned int adie_id; + int is_rc_mode; +}; + +struct conninfra_plat_data { + const unsigned int chip_id; + const void* hw_ops; + const void* reg_ops; + const void* platform_emi_ops; + const void* platform_pmic_ops; +}; + +extern struct consys_hw_env conn_hw_env[AIDE_NUM_MAX]; +extern struct consys_base_addr conn_reg; +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +int mtk_conninfra_drv_init(struct conninfra_dev_cb *dev_cb); +int mtk_conninfra_drv_deinit(void); + +int consys_hw_pwr_on(unsigned int curr_status, unsigned int on_radio); +int consys_hw_pwr_off(unsigned int curr_status, unsigned int off_radio); + +int consys_hw_wifi_power_ctl(unsigned int enable); +int consys_hw_bt_power_ctl(unsigned int enable); +int consys_hw_gps_power_ctl(unsigned int enable); +int consys_hw_fm_power_ctl(unsigned int enable); +int consys_hw_pmic_event_cb(unsigned int id, unsigned int event); + +unsigned int consys_hw_chipid_get(void); + +int consys_hw_get_clock_schematic(void); +unsigned int consys_hw_get_hw_ver(void); + +/******************************************************************************* +* tempoary for STEP +******************************************************************************** +*/ +/* + * return + * 1 : can read + * 0 : can't read + * -1: not consys register + */ +int consys_hw_reg_readable(void); +int consys_hw_is_connsys_reg(phys_addr_t addr); +/* + * 0 means NO hang + * > 0 means hang!! + */ +int consys_hw_is_bus_hang(void); +int consys_hw_dump_bus_status(void); + +int consys_hw_spi_read(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data); +int consys_hw_spi_write(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data); + +int consys_hw_adie_top_ck_en_on(enum consys_drv_type type); +int consys_hw_adie_top_ck_en_off(enum consys_drv_type type); + +/* NOTE: debug only*/ +int consys_hw_force_conninfra_wakeup(void); +int consys_hw_force_conninfra_sleep(void); + +int consys_hw_spi_clock_switch(enum connsys_spi_speed_type type); + +struct platform_device *get_consys_device(void); +struct consys_base_addr *get_conn_reg_base_addr(void); + +int consys_hw_dump_power_state(void); +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_CONSYS_HW_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/include/consys_reg_base.h b/package/mtk/drivers/conninfra/src/platform/include/consys_reg_base.h new file mode 100644 index 0000000000..b16dc6217b --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/include/consys_reg_base.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_CONSYS_REG_BASE_H_ +#define _PLATFORM_CONSYS_REG_BASE_H_ + +struct consys_reg_base_addr { + unsigned long phy_addr; + unsigned long long size; + unsigned long vir_addr; +}; + +#endif /* _PLATFORM_CONSYS_REG_BASE_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/include/consys_reg_mng.h b/package/mtk/drivers/conninfra/src/platform/include/consys_reg_mng.h new file mode 100644 index 0000000000..57f08af9a2 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/include/consys_reg_mng.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_CONSYS_REG_MNG_H_ +#define _PLATFORM_CONSYS_REG_MNG_H_ + +#include + +#include "consys_hw.h" + +enum conn_dump_cpupcr_type +{ + CONN_DUMP_CPUPCR_TYPE_BT = 1, + CONN_DUMP_CPUPCR_TYPE_WF = 2, + CONN_DUMP_CPUPCR_TYPE_ALL = 3, +}; + +struct consys_reg_mng_ops { + int(*consys_reg_mng_init) (struct platform_device *pdev); + int(*consys_reg_mng_deinit) (void); + int(*consys_reg_mng_check_reable) (void); + int(*consys_reg_mng_is_consys_reg) (unsigned int addr); + int(*consys_reg_mng_is_bus_hang) (void); + int(*consys_reg_mng_dump_bus_status) (void); + int(*consys_reg_mng_dump_conninfra_status) (void); + int(*consys_reg_mng_dump_cpupcr) (enum conn_dump_cpupcr_type, int times, unsigned long interval_us); + int(*consys_reg_mng_is_host_csr) (unsigned long addr); +}; + +int consys_reg_mng_init(struct platform_device *pdev, const struct conninfra_plat_data* plat_data); +int consys_reg_mng_deinit(void); +int consys_reg_mng_reg_readable(void); +int consys_reg_mng_is_connsys_reg(phys_addr_t addr); +int consys_reg_mng_reg_read(unsigned long addr, unsigned int *value, unsigned int mask); +int consys_reg_mng_reg_write(unsigned long addr, unsigned int value, unsigned int mask); +int consys_reg_mng_is_bus_hang(void); +int consys_reg_mng_dump_bus_status(void); +int consys_reg_mng_dump_conninfra_status(void); +int consys_reg_mng_dump_cpupcr(enum conn_dump_cpupcr_type dump_type, int times, unsigned long interval_us); +int consys_reg_mng_is_host_csr(unsigned long addr); + +#endif /* _PLATFORM_CONSYS_REG_MNG_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/include/consys_reg_util.h b/package/mtk/drivers/conninfra/src/platform/include/consys_reg_util.h new file mode 100644 index 0000000000..65ddc05bdb --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/include/consys_reg_util.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_CONSYS_REG_UTIL_H_ +#define _PLATFORM_CONSYS_REG_UTIL_H_ + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +/* platform dependent */ +#include "plat_def.h" + +#ifndef BIT +#define BIT(x) (1<<(x)) +#endif + +#define KBYTE (1024*sizeof(char)) +#ifndef GENMASK +#define GENMASK(h, l) \ + (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) +#endif + +#define GET_BIT_MASK(value, mask) ((value) & (mask)) +#define SET_BIT_MASK(pdest, value, mask) (*(pdest) = (GET_BIT_MASK(*(pdest), ~(mask)) | GET_BIT_MASK(value, mask))) +#define GET_BIT_RANGE(data, end, begin) ((data) & GENMASK(end, begin)) +#define SET_BIT_RANGE(pdest, data, end, begin) (SET_BIT_MASK(pdest, data, GENMASK(end, begin))) + +#define CONSYS_SET_BIT(REG, BITVAL) (*((volatile unsigned int *)(REG)) |= ((unsigned int)(BITVAL))) +#define CONSYS_CLR_BIT(REG, BITVAL) ((*(volatile unsigned int *)(REG)) &= ~((unsigned int)(BITVAL))) +#define CONSYS_CLR_BIT_WITH_KEY(REG, BITVAL, KEY) {\ + unsigned int val = (*(volatile unsigned int *)(REG)); \ + val &= ~((unsigned int)(BITVAL)); \ + val |= ((unsigned int)(KEY)); \ + (*(volatile unsigned int *)(REG)) = val;\ +} +#define CONSYS_REG_READ(addr) (*((volatile unsigned int *)(addr))) +#define CONSYS_REG_READ_BIT(addr, BITVAL) (*((volatile unsigned int *)(addr)) & ((unsigned int)(BITVAL))) +#define CONSYS_REG_WRITE(addr, data) mt_reg_sync_writel(data, addr) +#define CONSYS_REG_WRITE_RANGE(reg, data, end, begin) {\ + unsigned int val = CONSYS_REG_READ(reg); \ + SET_BIT_RANGE(&val, data, end, begin); \ + CONSYS_REG_WRITE(reg, val); \ +} +#define CONSYS_REG_WRITE_MASK(reg, data, mask) {\ + unsigned int val = CONSYS_REG_READ(reg); \ + SET_BIT_MASK(&val, data, mask); \ + CONSYS_REG_WRITE(reg, val); \ +} + +/* + * Write value with value_offset bits of right shift and size bits, + * to the reg_offset-th bit of address reg + * value -----------XXXXXXXXXXXX------------------- + * |<--size-->|<--value_offset-->| + * reg -------------OOOOOOOOOOOO----------------- + * |<--size-->|<--reg_offset-->| + * result -------------XXXXXXXXXXXX----------------- + */ +#define CONSYS_REG_WRITE_OFFSET_RANGE(reg, value, reg_offset, value_offset, size) ({\ + unsigned int data = (value) >> (value_offset); \ + data = GET_BIT_RANGE(data, size, 0); \ + data = data << (reg_offset); \ + CONSYS_REG_WRITE_RANGE(reg, data, ((reg_offset) + ((size) - 1)), reg_offset); \ +}) + +#define CONSYS_REG_WRITE_BIT(reg, offset, val) CONSYS_REG_WRITE_OFFSET_RANGE(reg, ((val) & 1), offset, 0, 1) + +#define CONSYS_REG_BIT_POLLING(addr, bit_index, exp_val, loop, delay, success) {\ + unsigned int polling_count = 0; \ + unsigned int reg_value = 0; \ + success = 0; \ + reg_value = (CONSYS_REG_READ_BIT(addr, (0x1 << bit_index)) >> bit_index); \ + while (reg_value != exp_val) { \ + if (polling_count > loop) { \ + success = -1; \ + break; \ + } \ + reg_value = (CONSYS_REG_READ_BIT(addr, (0x1 << bit_index)) >> bit_index); \ + udelay(delay); \ + polling_count++; \ + } \ +} + +#define CONSYS_REG_POLLING_LARGER_OR_EQUAL(addr, mask, bit_index, exp_val, loop, delay, success) {\ + unsigned int polling_count = 0; \ + unsigned int reg_value = 0; \ + success = 0; \ + reg_value = ((CONSYS_REG_READ(addr) & mask) >> bit_index); \ + while (reg_value < exp_val) { \ + if (polling_count > loop) { \ + success = -1; \ + break; \ + } \ + reg_value = ((CONSYS_REG_READ(addr) & mask) >> bit_index); \ + udelay(delay); \ + polling_count++; \ + } \ +} + +#define CONSYS_REG_POLLING_EQUAL(addr, mask, bit_index, exp_val, loop, delay, success) {\ + unsigned int polling_count = 0; \ + unsigned int reg_value = 0; \ + success = 0; \ + reg_value = ((CONSYS_REG_READ(addr) & mask) >> bit_index); \ + while (reg_value != exp_val) { \ + if (polling_count > loop) { \ + success = -1; \ + break; \ + } \ + reg_value = ((CONSYS_REG_READ(addr) & mask) >> bit_index); \ + udelay(delay); \ + polling_count++; \ + } \ +} + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_CONSYS_REG_UTIL_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/include/emi_mng.h b/package/mtk/drivers/conninfra/src/platform/include/emi_mng.h new file mode 100644 index 0000000000..93e619e632 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/include/emi_mng.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_EMI_MNG_H_ +#define _PLATFORM_EMI_MNG_H_ + +#include +#include +#include "osal.h" + +#include "consys_hw.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +struct consys_emi_addr_info { + /* This include BT/WF FW and WFDMA */ + phys_addr_t emi_ap_phy_base; + unsigned int emi_ap_phy_size; + unsigned int fw_emi_size; +}; + +typedef int(*CONSYS_IC_EMI_SET_REGION_PROTECTION) (void); +typedef int(*CONSYS_IC_EMI_SET_REMAPPING_REG) (void); +typedef unsigned int (*CONSYS_IC_GET_FW_EMI_SIZE)(void); + +struct consys_platform_emi_ops { + CONSYS_IC_EMI_SET_REGION_PROTECTION consys_ic_emi_set_region_protection; + CONSYS_IC_EMI_SET_REMAPPING_REG consys_ic_emi_set_remapping_reg; + CONSYS_IC_GET_FW_EMI_SIZE consys_ic_emi_get_fw_emi_size; +}; + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int emi_mng_init(struct platform_device *pdev, const struct conninfra_plat_data* plat_data); +int emi_mng_deinit(void); + +int emi_mng_set_region_protection(void); +int emi_mng_set_remapping_reg(void); +struct consys_emi_addr_info* emi_mng_get_phy_addr(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_EMI_MNG_H_ */ + diff --git a/package/mtk/drivers/conninfra/src/platform/include/plat_def.h b/package/mtk/drivers/conninfra/src/platform/include/plat_def.h new file mode 100644 index 0000000000..7c2a4f62b9 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/include/plat_def.h @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_DEF_H_ +#define _PLATFORM_DEF_H_ + +#include +#include + +#define mt_reg_sync_writel(v, a) \ + do { \ + writel((v), (void __force __iomem *)((a))); \ + mb(); \ + } while (0) + +#endif /* _PLATFORM_DEF_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/include/pmic_mng.h b/package/mtk/drivers/conninfra/src/platform/include/pmic_mng.h new file mode 100644 index 0000000000..8ee3243732 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/include/pmic_mng.h @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_PMIC_MNG_H_ +#define _PLATFORM_PMIC_MNG_H_ + +#include + +#include "consys_hw.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +typedef int(*CONSYS_PMIC_GET_FROM_DTS) ( + struct platform_device *pdev, + struct conninfra_dev_cb* dev_cb); + +typedef int(*CONSYS_PMIC_COMMON_POWER_CTRL) (unsigned int enable); + +typedef int(*CONSYS_PMIC_WIFI_POWER_CTRL) (unsigned int enable); +typedef int(*CONSYS_PMIC_BT_POWER_CTRL) (unsigned int enable); +typedef int(*CONSYS_PMIC_GPS_POWER_CTRL) (unsigned int enable); +typedef int(*CONSYS_PMIC_FM_POWER_CTRL) (unsigned int enable); +typedef int(*CONSYS_PMIC_EVENT_NOTIFIER) (unsigned int id, unsigned int event); + +struct consys_platform_pmic_ops { + CONSYS_PMIC_GET_FROM_DTS consys_pmic_get_from_dts; + /* vcn 18 */ + CONSYS_PMIC_COMMON_POWER_CTRL consys_pmic_common_power_ctrl; + CONSYS_PMIC_WIFI_POWER_CTRL consys_pmic_wifi_power_ctrl; + CONSYS_PMIC_BT_POWER_CTRL consys_pmic_bt_power_ctrl; + CONSYS_PMIC_GPS_POWER_CTRL consys_pmic_gps_power_ctrl; + CONSYS_PMIC_FM_POWER_CTRL consys_pmic_fm_power_ctrl; + CONSYS_PMIC_EVENT_NOTIFIER consys_pmic_event_notifier; +}; + + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +int pmic_mng_init( + struct platform_device *pdev, + struct conninfra_dev_cb* dev_cb, + const struct conninfra_plat_data* plat_data); +int pmic_mng_deinit(void); + +int pmic_mng_common_power_ctrl(unsigned int enable); +int pmic_mng_wifi_power_ctrl(unsigned int enable); +int pmic_mng_bt_power_ctrl(unsigned int enable); +int pmic_mng_gps_power_ctrl(unsigned int enable); +int pmic_mng_fm_power_ctrl(unsigned int enable); +int pmic_mng_event_cb(unsigned int id, unsigned int event); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_PMIC_MNG_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981.h b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981.h new file mode 100644 index 0000000000..48b1e2786d --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7981_H_ +#define _PLATFORM_MT7981_H_ + +enum +{ + ADIE_TYPE_NONE = 0, + ADIE_TYPE_ONE, + ADIE_TYPE_TWO, + ADIE_TYPE_NUM_MAX +}; + +enum conn_semaphore_type +{ + CONN_SEMA_CHIP_POWER_ON_INDEX = 0, + CONN_SEMA_CALIBRATION_INDEX = 1, + CONN_SEMA_FW_DL_INDEX = 2, + CONN_SEMA_CLOCK_SWITCH_INDEX = 3, + CONN_SEMA_CCIF_INDEX = 4, + CONN_SEMA_COEX_INDEX = 5, + CONN_SEMA_USB_EP0_INDEX = 6, + CONN_SEMA_USB_SHARED_INFO_INDEX = 7, + CONN_SEMA_USB_SUSPEND_INDEX = 8, + CONN_SEMA_USB_RESUME_INDEX = 9, + CONN_SEMA_PCIE_INDEX = 10, + CONN_SEMA_RFSPI_INDEX = 11, + CONN_SEMA_EFUSE_INDEX = 12, + CONN_SEMA_THERMAL_INDEX = 13, + CONN_SEMA_FLASH_INDEX = 14, + CONN_SEMA_DEBUG_INDEX = 15, + CONN_SEMA_WIFI_LP_INDEX = 16, + CONN_SEMA_PATCH_DL_INDEX = 17, + CONN_SEMA_SHARED_VAR_INDEX = 18, + CONN_SEMA_CONN_INFRA_COMMON_SYSRAM_INDEX = 19, + CONN_SEMA_NUM_MAX = 32 /* can't be omitted */ +}; + +unsigned int consys_soc_chipid_get(void); +unsigned int consys_get_hw_ver(void); + + +#endif /* _PLATFORM_MT7981_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_consys_reg.h b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_consys_reg.h new file mode 100644 index 0000000000..ffa8b5c398 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_consys_reg.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7981_CONSYS_REG_H_ +#define _PLATFORM_MT7981_CONSYS_REG_H_ + +#include "consys_reg_base.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +enum consys_base_addr_index { + TOP_MISC_BASE = 0, /* top_misc */ + TOPRGU_BASE = 1, /* TOPRGU */ + GPIO_BASE = 2, /* GPIO */ + IOCFG_TM_BASE = 3, /* IOCFG_TM */ + IOCFG_LT_BASE = 4, /* IOCFG_LT */ + INFRACFG_AO_BASE = 5, /* infracfg_ao_auto_gen_reg */ + CONN_INFRA_CFG_BASE = 6, /* conn_infra_cfg */ + CONN_INFRA_SYSRAM_BASE = 7, /* conn_infra_sysram */ + CONN_INFRA_CLKGEN_ON_TOP_BASE = 8, /* conn_infra_clkgen_on_top */ + CONN_HOST_CSR_TOP_BASE = 9, /* conn_host_csr_top */ + CONN_INFRA_BUS_CR_BASE = 10, /* conn_infra_bus_cr */ + CONN_INFRA_RGU_BASE = 11, /* conn_infra_rgu */ + CONN_WT_SLP_CTL_REG_BASE = 12, /* conn_wt_slp_ctl_reg */ + INST2_CONN_WT_SLP_CTL_REG_BASE = 13, /* Inst2_conn_wt_slp_ctl_reg */ + CONN_RF_SPI_MST_REG_BASE = 14, /* conn_rf_spi_mst_reg */ + INST2_CONN_RF_SPI_MST_REG_BASE = 15, /* Inst2_conn_rf_spi_mst_reg */ + CONN_SEMAPHORE_BASE = 16, /* conn_semaphore */ + CONN_AFE_CTL_BASE = 17, /* conn_afe_ctl */ + CONN_AFE_CTL_2ND_BASE = 18, /* conn_afe_ctl_2nd */ + WF_TOP_SLPPROT_ON_BASE = 19, /* wf_top_slpprot_on by remapping to 0x81020000 */ + WF_TOP_CFG_BASE = 20, /* wf_top_cfg by remapping to 0x80020000 */ + WF_MCU_CONFIG_LS_BASE = 21, /* wf_mcu_confg_ls by remapping to 0x88000000 */ + WF_MCU_BUS_CR_BASE = 22, /* wf_mcu_bus_cr by remapping to 0x830C0XXX */ + WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_BASE = 23, /* wf_mcusys_infra_bus_full_u_debug_ctrl_ao by remapping to 0x810F0000 */ + WF_TOP_CFG_ON_BASE = 24, /* wf_top_cfg_on by remapping to 0x81021000 */ + CONSYS_BASE_ADDR_MAX +}; + +struct consys_base_addr { + struct consys_reg_base_addr reg_base_addr[CONSYS_BASE_ADDR_MAX]; +}; + +extern struct consys_base_addr conn_reg; + +#define REG_TOP_MISC_ADDR conn_reg.reg_base_addr[TOP_MISC_BASE].vir_addr +#define REG_TOP_RGU_ADDR conn_reg.reg_base_addr[TOPRGU_BASE].vir_addr +#define REG_GPIO_BASE_ADDR conn_reg.reg_base_addr[GPIO_BASE].vir_addr +#define REG_IOCFG_TM_ADDR conn_reg.reg_base_addr[IOCFG_TM_BASE].vir_addr +#define REG_IOCFG_LT_ADDR conn_reg.reg_base_addr[IOCFG_LT_BASE].vir_addr +#define REG_INFRACFG_AO_ADDR conn_reg.reg_base_addr[INFRACFG_AO_BASE].vir_addr +#define REG_CONN_INFRA_CFG_ADDR conn_reg.reg_base_addr[CONN_INFRA_CFG_BASE].vir_addr +#define REG_CONN_INFRA_SYSRAM_ADDR conn_reg.reg_base_addr[CONN_INFRA_SYSRAM_BASE].vir_addr +#define REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR conn_reg.reg_base_addr[CONN_INFRA_CLKGEN_ON_TOP_BASE].vir_addr +#define REG_CONN_HOST_CSR_TOP_ADDR conn_reg.reg_base_addr[CONN_HOST_CSR_TOP_BASE].vir_addr +#define REG_CONN_INFRA_BUS_CR_ADDR conn_reg.reg_base_addr[CONN_INFRA_BUS_CR_BASE].vir_addr +#define REG_CONN_INFRA_RGU_ADDR conn_reg.reg_base_addr[CONN_INFRA_RGU_BASE].vir_addr +#define REG_CONN_WT_SLP_CTL_REG_ADDR conn_reg.reg_base_addr[CONN_WT_SLP_CTL_REG_BASE].vir_addr +#define REG_INST2_CONN_WT_SLP_CTL_REG_ADDR conn_reg.reg_base_addr[INST2_CONN_WT_SLP_CTL_REG_BASE].vir_addr +#define REG_CONN_RF_SPI_MST_REG_ADDR conn_reg.reg_base_addr[CONN_RF_SPI_MST_REG_BASE].vir_addr +#define REG_INST2_CONN_RF_SPI_MST_REG_ADDR conn_reg.reg_base_addr[INST2_CONN_RF_SPI_MST_REG_BASE].vir_addr +#define REG_CONN_SEMAPHORE_ADDR conn_reg.reg_base_addr[CONN_SEMAPHORE_BASE].vir_addr +#define REG_CONN_AFE_CTL_ADDR conn_reg.reg_base_addr[CONN_AFE_CTL_BASE].vir_addr +#define REG_CONN_AFE_CTL_2ND_ADDR conn_reg.reg_base_addr[CONN_AFE_CTL_2ND_BASE].vir_addr +#define REG_WF_TOP_SLPPROT_ON_ADDR conn_reg.reg_base_addr[WF_TOP_SLPPROT_ON_BASE].vir_addr +#define REG_WF_TOP_CFG_ADDR conn_reg.reg_base_addr[WF_TOP_CFG_BASE].vir_addr +#define REG_WF_MCU_CONFIG_LS_ADDR conn_reg.reg_base_addr[WF_MCU_CONFIG_LS_BASE].vir_addr +#define REG_WF_MCU_BUS_CR_ADDR conn_reg.reg_base_addr[WF_MCU_BUS_CR_BASE].vir_addr +#define REG_WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_ADDR conn_reg.reg_base_addr[WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_BASE].vir_addr +#define REG_WF_TOP_CFG_ON_ADDR conn_reg.reg_base_addr[WF_TOP_CFG_ON_BASE].vir_addr + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +struct consys_base_addr* get_conn_reg_base_addr(void); + +#endif /* _PLATFORM_MT7981_CONSYS_REG_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_consys_reg_offset.h b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_consys_reg_offset.h new file mode 100644 index 0000000000..bd50361d04 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_consys_reg_offset.h @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7981_CONSYS_REG_OFFSET_H_ +#define _PLATFORM_MT7981_CONSYS_REG_OFFSET_H_ + +/**********************************************************************/ +/* Base: TOP_MISC (0x11D1_0000) */ +/**********************************************************************/ +#define CONNSYS_MISC 0x0114 +#define TOP_MISC_RSRV_ALL1_3 0x021C + + +/**********************************************************************/ +/* Base: TOP RGU (0x1001_C000) */ +/**********************************************************************/ +#define TOP_RGU_WDT_SWSYSRST 0x0018 + +/**********************************************************************/ +/* Base: GPIO (0x11D0_0000) */ +/**********************************************************************/ +#define GPIO_MODE5 0x0350 +#define GPIO_MODE6 0x0360 +#define GPIO_MODE7 0x0370 + +/**********************************************************************/ +/* Base: IOCFG_TM (0x11F0_0000) */ +/**********************************************************************/ +#define IOCFG_TM_DRV_CFG0 0x0000 +#define IOCFG_TM_DRV_CFG1 0x0010 + +/**********************************************************************/ +/* Base: IOCFG_LT (0x11F1_0000) */ +/**********************************************************************/ +#define IOCFG_LT_DRV_CFG0 0x0000 +#define IOCFG_LT_DRV_CFG1 0x0010 + +/**********************************************************************/ +/* Base: INFRACFG_AO (0x1000_3000) */ +/**********************************************************************/ +#define CONN2AP_GALS_SLPPROT 0x00D0 +#define AP2CONN_GALS_SLPPROT 0x00D4 + +/**********************************************************************/ +/* Base: CONN_INFRA_CFG (0x1800_1000) */ +/**********************************************************************/ +#define CONN_INFRA_CFG_IP_VERSION 0x0000 +#define EFUSE 0x0020 +#define ADIE_CTL 0x0030 +#define CONN_INFRA_CFG_PWRCTRL0 0x0200 +#define CONN_INFRA_CFG_RC_CTL_0 0x0380 +#define OSC_CTL_0 0x0300 +#define EMI_CTL_WF 0x0414 +#define CONN_INFRA_WF_SLP_CTRL 0x0540 +#define CONN_INFRA_WF_SLP_STATUS 0x0544 + +/**********************************************************************/ +/* Base: CONN_INFRA_SYSRAM (0x1805_0000) */ +/**********************************************************************/ +#define SYSRAM_BASE_ADDR 0x0000 + +/**********************************************************************/ +/* Base: CONN_INFRA_CLKGEN_ON_TOP (0x1800_9000) */ +/**********************************************************************/ +#define CKGEN_BUS_WPLL_DIV_1 0x0008 +#define CKGEN_BUS_WPLL_DIV_2 0x000C +#define CKGEN_RFSPI_WPLL_DIV 0x0040 +#define CKGEN_BUS 0x0A00 + +/**********************************************************************/ +/* Base: CONN_HOST_CSR_TOP (0x1806_0000) */ +/**********************************************************************/ +#define CONN_INFRA_WAKEPU_TOP 0x01A0 +#define CONN_INFRA_WAKEPU_WF 0x01A4 +#define CONN2AP_REMAP_MCU_EMI 0x01C4 +#define CONN2AP_REMAP_WF_PERI 0x01D4 +#define CONN2AP_RSVD_PERI_REGION1 0x01D8 +#define DBG_DUMMY_3 0x02CC + +/**********************************************************************/ +/* Base: CONN_INFRA_BUS_CR (0x1800_E000) */ +/**********************************************************************/ +#define CONN_INFRA_BUS_OFF_TIMEOUT_CTRL 0x0300 +#define CONN_INFRA_BUS_ON_TIMEOUT_CTRL 0x031C +#define CONN2AP_EMI_PATH_ADDR_START 0x0360 +#define CONN2AP_EMI_PATH_ADDR_END 0x0364 + +/**********************************************************************/ +/* Base: CONN_INFRA_RGU (0x1800_0000) */ +/**********************************************************************/ +#define WFSYS_ON_TOP_PWR_CTL 0x0010 +#define BGFYS_ON_TOP_PWR_CTL 0x0020 +#define SYSRAM_HWCTL_PDN 0x0050 +#define SYSRAM_HWCTL_SLP 0x0054 +#define WFSYS_CPU_SW_RST_B 0x0120 + +/**********************************************************************/ +/* Base: CONN_WT_SLP_CTL_REG (0x1800_5000) */ +/* Base: INST2_CONN_WT_SLP_CTL_REG (0x1808_5000) */ +/**********************************************************************/ +#define WB_WF_CK_ADDR 0x0070 +#define WB_WF_WAKE_ADDR 0x0074 +#define WB_WF_ZPS_ADDR 0x0078 +#define WB_TOP_CK_ADDR 0x0084 +#define WB_WF_B0_CMD_ADDR 0x008C +#define WB_WF_B1_CMD_ADDR 0x0090 +#define WB_SLP_TOP_CK_0 0x0120 +#define WB_SLP_TOP_CK_1 0x0124 + +/**********************************************************************/ +/* Base: CONN_RF_SPI_MST_REG (0x1800_4000) */ +/* Base: INST2_CONN_RF_SPI_MST_REG (0x1808_4000) */ +/**********************************************************************/ +#define SPI_STA 0x0000 +#define SPI_WF_ADDR 0x0010 +#define SPI_WF_WDAT 0x0014 +#define SPI_WF_RDAT 0x0018 +#define SPI_BT_ADDR 0x0020 +#define SPI_BT_WDAT 0x0024 +#define SPI_BT_RDAT 0x0028 +#define SPI_FM_ADDR 0x0030 +#define SPI_FM_WDAT 0x0034 +#define SPI_FM_RDAT 0x0038 +#define SPI_GPS_ADDR 0x0040 +#define SPI_GPS_WDAT 0x0044 +#define SPI_GPS_RDAT 0x0048 +#define SPI_TOP_ADDR 0x0050 +#define SPI_TOP_WDAT 0x0054 +#define SPI_TOP_RDAT 0x0058 + +/**********************************************************************/ +/* Base: CONN_SEMAPHORE_BASE (0x1807_0000) */ +/**********************************************************************/ +#define CONN_SEMA00_M2_OWN_STA 0x2000 +#define CONN_SEMA00_M2_OWN_REL 0x2200 +#define CONN_SEMA_OWN_BY_M0_STA_REP 0x0400 +#define CONN_SEMA_OWN_BY_M1_STA_REP 0x1400 +#define CONN_SEMA_OWN_BY_M2_STA_REP 0x2400 +#define CONN_SEMA_OWN_BY_M3_STA_REP 0x3400 +#define CONN_SEMA_OWN_BY_M4_STA_REP 0x4400 +#define CONN_SEMA_OWN_BY_M5_STA_REP 0x5400 +#define CONN_SEMA_OWN_BY_M6_STA_REP 0x6400 +#define CONN_SEMA_OWN_BY_M7_STA_REP 0x7400 + +/**********************************************************************/ +/* Base: CONN_AFE_CTL_BASE (0x1800_3000) */ +/* Base: CONN_AFE_CTL_2ND_BASE (0x1808_3000) */ +/**********************************************************************/ +#define RG_DIG_EN_01 0x0000 +#define RG_DIG_EN_02 0x0004 +#define RG_DIG_EN_03 0x0008 +#define RG_DIG_TOP_01 0x000C +#define RG_PLL_STB_TIME 0x00F4 + +/**********************************************************************/ +/* Base: WF_TOP_SLPPROT_ON_BASE (0x8102_0000 remap to 0x184C_0000) */ +/**********************************************************************/ +#define WF_TOP_SLPPROT_ON_STATUS_READ 0x300C + +/**********************************************************************/ +/* Base: WF_TOP_CFG_BASE (0x8002_0000 remap to 0x184B_0000) */ +/**********************************************************************/ +#define WF_TOP_CFG_IP_VERSION 0x0010 + +/**********************************************************************/ +/* Base: WF_MCU_CONFIG_LS_BASE (0x8800_0000 remap to 0x184F_0000) */ +/**********************************************************************/ +#define BUSHANGCR 0x0440 + +/**********************************************************************/ +/* Base: WF_MCU_BUS_CR_BASE (0x830C_0XXX remap to 0x1840_0XXX) */ +/**********************************************************************/ +#define AP2WF_REMAP_1 0x0120 + +/**********************************************************************/ +/* Base: WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_BASE (0x810F_0000 remap to 0x1850_0000) */ +/**********************************************************************/ +#define WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_WFMCU_PWA_CTRL0 0x0000 + +/**********************************************************************/ +/* Base: WF_TOP_CFG_ON_BASE (0x8102_1000 remap to 0x184C_0000) */ +/**********************************************************************/ +#define ROMCODE_INDEX 0x1604 + +/**********************************************************************/ +/* A-die CR */ +/**********************************************************************/ +#define ATOP_CHIP_ID 0x02C +#define ATOP_TOP_CLK_EN 0xA00 +#define ATOP_RG_ENCAL_WBTAC_IF_SW 0x070 +#define ATOP_RG_WRI_CK_SELECT 0x4AC +#define ATOP_EFUSE_CTRL_1 0x108 +#define ATOP_EFUSE_CTRL_2 0x148 +#define ATOP_EFUSE_CTRL_3 0x14C +#define ATOP_EFUSE_CTRL_4 0x15C +#define ATOP_EFUSE_RDATA0 0x130 +#define ATOP_EFUSE_RDATA1 0x134 +#define ATOP_EFUSE_RDATA2 0x138 +#define ATOP_EFUSE_RDATA3 0x13C +#define ATOP_RG_EFUSE_CFG5 0x144 +#define ATOP_THADC_ANALOG 0x3A6 +#define ATOP_THADC_SLOP 0x3A7 +#define ATOP_RG_TOP_THADC_BG 0x034 +#define ATOP_RG_TOP_THADC_00 0x038 + +#define ATOP_XTAL_TRIM_FLOW 0x3AC +#define ATOP_XTAL_CR_C1_SEL_AXM_80M_OSC 0x390 +#define ATOP_XTAL_CR_C1_SEL_AXM_40M_OSC 0x391 +#define ATOP_XTAL_CR_C1_SEL_AXM_TRIM1_80M_OSC 0x398 +#define ATOP_XTAL_CR_C1_SEL_AXM_TRIM1_40M_OSC 0x399 +#define ATOP_RG_STRAP_PIN_IN 0x4FC +#define ATOP_RG_XO_01 0x65C +#define ATOP_RG_XO_03 0x664 + + +#define ATOP_7975_XTAL_CALIBRATION 0x3A1 +#define ATOP_7975_XTAL_TRIM2_COMPENSATION 0x3A2 +#define ATOP_7975_XTAL_TRIM3_COMPENSATION 0x3A3 +#define ATOP_7975_XTAL_TRIM4_COMPENSATION 0x3A4 +#define ATOP_7975_XTAL_TRIM_FLOW 0x3A5 +#define ATOP_7975_CR_C1_C2_A94 0xA94 +#define ATOP_7975_CR_C1_C2_A18 0xA18 +#define ATOP_7975_CR_C1_C2_A84 0xA84 +#define ATOP_7975_CR_C1_C2_AA4 0xAA4 + + + +#endif /* _PLATFORM_MT7981_CONSYS_REG_OFFSET_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_emi.h b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_emi.h new file mode 100644 index 0000000000..6d395748ba --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_emi.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7981_EMI_H_ +#define _PLATFORM_MT7981_EMI_H_ + +#include "osal.h" +#include "emi_mng.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +struct consys_platform_emi_ops* get_consys_platform_emi_ops(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_MT7981_EMI_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_pmic.h b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_pmic.h new file mode 100644 index 0000000000..8f597918d5 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_pmic.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7981_PMIC_H_ +#define _PLATFORM_MT7981_PMIC_H_ + +#include "osal.h" +#include "pmic_mng.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +struct consys_platform_pmic_ops* get_consys_platform_pmic_ops(void); + +#endif /* _PLATFORM_MT7981_PMIC_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_pos.h b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_pos.h new file mode 100644 index 0000000000..997e68454b --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/include/mt7981_pos.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7981_POS_H_ +#define _PLATFORM_MT7981_POS_H_ + +int consys_plt_hw_init(void); +int consys_xtal_ctrl_fast_mode(void); +int consys_sw_reset_ctrl(bool bassert); +int consys_tx_rx_bus_slp_prot_ctrl(bool enable); +void consys_set_if_pinmux(bool enable); +int consys_polling_chipid(void); +int consys_plt_adie_type_cfg(void); +int consys_bus_clock_ctrl(enum consys_drv_type drv_type, unsigned int bus_clock); +int consys_emi_set_remapping_reg(void); +int consys_emi_set_region_protection(void); +int connsys_d_die_cfg(void); +int connsys_conninfra_sysram_hw_ctrl(void); +int connsys_spi_master_cfg(void); +int consys_sema_acquire_timeout(unsigned int index, unsigned int usec); +void consys_sema_release(unsigned int index); +int consys_spi_read(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data); +int consys_spi_write(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data); +int consys_spi_write_offset_range(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int value, + unsigned int reg_offset, unsigned int value_offset, unsigned int size); +int connsys_a_die_cfg(void); +int connsys_afe_wbg_cal(void); +int connsys_subsys_pll_initial(void); +int connsys_osc_legacy_mode(void); +int connsys_top_pwr_ctrl(void); +int connsys_conn_infra_bus_timeout(void); +int connsys_clkgen_wpll_hw_ctrl(void); +int consys_conninfra_top_wakeup(void); +int consys_conninfra_top_sleep(void); +int consys_adie_top_ck_en_on_off_ctrl(enum consys_drv_type type, unsigned char on); +int consys_conninfra_wf_wakeup(void); +int consys_conninfra_wf_sleep(void); +int consys_conn_wmcpu_sw_reset(bool bassert); +int consys_wf_bus_slp_prot_ctrl(bool enable); +int consys_wfsys_top_on_ctrl(bool enable); +int consys_wfsys_bus_slp_prot_check(bool enable); +int consys_wfsys_bus_timeout_ctrl(void); +int consys_wmcpu_idle_loop_check(void); +int consys_wpll_ctrl(bool enable); +int consys_conninfra_wf_req_clr(void); + + +#endif /* _PLATFORM_MT7981_POS_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981.c b/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981.c new file mode 100644 index 0000000000..ac00ebc381 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981.c @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include + +#include "osal.h" +#include "conninfra.h" +#include "consys_hw.h" +#include "consys_reg_mng.h" +#include "consys_reg_util.h" +#include "mt7981.h" +#include "mt7981_pos.h" +#include "emi_mng.h" +#include "mt7981_consys_reg.h" +#include "mt7981_consys_reg_offset.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define PLATFORM_SOC_CHIP 0x7981 +#define CONN_IP_VER 0x02090000 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +struct consys_hw_ops_struct g_consys_hw_ops_mt7981 = { + /* HW init */ + .consys_plt_hw_init = consys_plt_hw_init, + + /* POS */ + .consys_plt_xtal_ctrl_fast_mode = consys_xtal_ctrl_fast_mode, + .consys_plt_connsys_sw_reset_ctrl = consys_sw_reset_ctrl, + .consys_plt_set_if_pinmux = consys_set_if_pinmux, + .consys_plt_tx_rx_bus_slp_prot_ctrl = consys_tx_rx_bus_slp_prot_ctrl, + .consys_plt_polling_consys_chipid = consys_polling_chipid, + .consys_plt_bus_clock_ctrl = consys_bus_clock_ctrl, + .consys_plt_d_die_cfg = connsys_d_die_cfg, + .consys_plt_conninfra_sysram_hw_ctrl = connsys_conninfra_sysram_hw_ctrl, + .consys_plt_spi_master_cfg = connsys_spi_master_cfg, + .consys_plt_a_die_cfg = connsys_a_die_cfg, + .consys_plt_afe_wbg_cal = connsys_afe_wbg_cal, + .consys_plt_subsys_pll_initial = connsys_subsys_pll_initial, + .consys_plt_osc_legacy_mode = connsys_osc_legacy_mode, + .consys_plt_top_pwr_ctrl = connsys_top_pwr_ctrl, + .consys_plt_conn_infra_bus_timeout = connsys_conn_infra_bus_timeout, + .consys_plt_clkgen_wpll_hw_ctrl = connsys_clkgen_wpll_hw_ctrl, + .consys_plt_conninfra_wakeup = consys_conninfra_top_wakeup, + .consys_plt_conninfra_sleep = consys_conninfra_top_sleep, + .consys_plt_adie_top_ck_en_on_off_ctrl = consys_adie_top_ck_en_on_off_ctrl, + .consys_plt_conninfra_wf_wakeup = consys_conninfra_wf_wakeup, + .consys_plt_conninfra_wf_sleep = consys_conninfra_wf_sleep, + .consys_plt_conn_wmcpu_sw_reset = consys_conn_wmcpu_sw_reset, + .consys_plt_wf_bus_slp_prot_ctrl = consys_wf_bus_slp_prot_ctrl, + .consys_plt_wfsys_top_on_ctrl = consys_wfsys_top_on_ctrl, + .consys_plt_wfsys_bus_slp_prot_check = consys_wfsys_bus_slp_prot_check, + .consys_plt_wfsys_bus_timeout_ctrl = consys_wfsys_bus_timeout_ctrl, + .consys_plt_conn_wmcpu_idle_loop_check = consys_wmcpu_idle_loop_check, + .consys_plt_wpll_ctrl = consys_wpll_ctrl, + .consys_plt_conninfra_wf_req_clr = consys_conninfra_wf_req_clr, + + /* load from dts */ + /* TODO: mtcmos should move to a independent module */ + .consys_plt_clk_get_from_dts = NULL, + .consys_plt_clk_detach = NULL, + + /* clock */ + .consys_plt_soc_chipid_get = consys_soc_chipid_get, + + /* debug */ + .consys_plt_get_hw_ver = consys_get_hw_ver, + .consys_plt_spi_read = consys_spi_read, + .consys_plt_spi_write = consys_spi_write, + .consys_plt_spi_clock_switch = NULL, + .consys_plt_power_state = NULL, + + /* others */ + .consys_plt_adie_type_cfg = consys_plt_adie_type_cfg, +}; + +/* For mt7981 */ +extern struct consys_hw_ops_struct g_consys_hw_ops_mt7981; +extern struct consys_reg_mng_ops g_dev_consys_reg_ops_mt7981; +extern struct consys_platform_emi_ops g_consys_platform_emi_ops_mt7981; +extern struct consys_platform_pmic_ops g_consys_platform_pmic_ops_mt7981; + +const struct conninfra_plat_data mt7981_plat_data = { + .chip_id = PLATFORM_SOC_CHIP, + .hw_ops = &g_consys_hw_ops_mt7981, + .reg_ops = &g_dev_consys_reg_ops_mt7981, + .platform_emi_ops = &g_consys_platform_emi_ops_mt7981, + .platform_pmic_ops = &g_consys_platform_pmic_ops_mt7981, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +unsigned int consys_soc_chipid_get(void) +{ + return PLATFORM_SOC_CHIP; +} + +unsigned int consys_get_hw_ver(void) +{ + return CONN_IP_VER; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_consys_reg.c b/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_consys_reg.c new file mode 100644 index 0000000000..fddcd1b148 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_consys_reg.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include +#include +#include +#include +#include +#include +#include "consys_reg_mng.h" +#include "mt7981_consys_reg.h" +#include "mt7981_consys_reg_offset.h" +#include "consys_hw.h" +#include "consys_reg_util.h" + +#define CFG_REG_LOAD_FROM_DTS_CTRL 0 + +static int consys_reg_init(struct platform_device *pdev); +static int consys_reg_deinit(void); + +struct consys_base_addr conn_reg = { + .reg_base_addr[TOP_MISC_BASE] = {0x11D10000, 0x1000, 0}, + .reg_base_addr[TOPRGU_BASE] = {0x1001C000, 0x1000, 0}, + .reg_base_addr[GPIO_BASE] = {0x11D00000, 0x1000, 0}, + .reg_base_addr[IOCFG_TM_BASE] = {0x11F00000, 0x1000, 0}, + .reg_base_addr[IOCFG_LT_BASE] = {0x11F10000, 0x1000, 0}, + .reg_base_addr[INFRACFG_AO_BASE] = {0x10003000, 0x1000, 0}, + .reg_base_addr[CONN_INFRA_CFG_BASE] = {0x18001000, 0x1000, 0}, + .reg_base_addr[CONN_INFRA_SYSRAM_BASE] = {0x18050000, 0x1000, 0}, + .reg_base_addr[CONN_INFRA_CLKGEN_ON_TOP_BASE] = {0x18009000, 0x1000, 0}, + .reg_base_addr[CONN_HOST_CSR_TOP_BASE] = {0x18060000, 0x1000, 0}, + .reg_base_addr[CONN_INFRA_BUS_CR_BASE] = {0x1800E000, 0x1000, 0}, + .reg_base_addr[CONN_INFRA_RGU_BASE] = {0x18000000, 0x1000, 0}, + .reg_base_addr[CONN_WT_SLP_CTL_REG_BASE] = {0x18005000, 0x1000, 0}, + .reg_base_addr[INST2_CONN_WT_SLP_CTL_REG_BASE] = {0x18085000, 0x1000, 0}, + .reg_base_addr[CONN_RF_SPI_MST_REG_BASE] = {0x18004000, 0x1000, 0}, + .reg_base_addr[INST2_CONN_RF_SPI_MST_REG_BASE] = {0x18084000, 0x1000, 0}, + .reg_base_addr[CONN_SEMAPHORE_BASE] = {0x18070000, 0x10000, 0}, + .reg_base_addr[CONN_AFE_CTL_BASE] = {0x18003000, 0x1000, 0}, + .reg_base_addr[CONN_AFE_CTL_2ND_BASE] = {0x18083000, 0x1000, 0}, + .reg_base_addr[WF_TOP_SLPPROT_ON_BASE] = {0x184C0000, 0x10000, 0}, + .reg_base_addr[WF_TOP_CFG_BASE] = {0x184B0000, 0x1000, 0}, + .reg_base_addr[WF_MCU_CONFIG_LS_BASE] = {0x184F0000, 0x1000, 0}, + .reg_base_addr[WF_MCU_BUS_CR_BASE] = {0x18400000, 0x1000, 0}, + .reg_base_addr[WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_BASE] = {0x18500000, 0x1000, 0}, + .reg_base_addr[WF_TOP_CFG_ON_BASE] = {0x184C0000, 0x10000, 0}, +}; + +const char* consys_base_addr_index_to_str[CONSYS_BASE_ADDR_MAX] = { + "TOP_MISC_BASE", + "TOPRGU_BASE", + "GPIO_BASE", + "IOCFG_TR_BASE", + "IOCFG_TL_BASE", + "INFRACFG_AO_BASE", + "CONN_INFRA_CFG_BASE", + "CONN_INFRA_SYSRAM_BASE", + "CONN_INFRA_CLKGEN_ON_TOP_BASE", + "CONN_HOST_CSR_TOP_BASE", + "CONN_INFRA_BUS_CR_BASE", + "CONN_INFRA_RGU_BASE", + "CONN_WT_SLP_CTL_REG_BASE", + "INST2_CONN_WT_SLP_CTL_REG_BASE", + "CONN_RF_SPI_MST_REG_BASE", + "INST2_CONN_RF_SPI_MST_REG_BASE", + "CONN_SEMAPHORE_BASE", + "CONN_AFE_CTL_BASE", + "CONN_AFE_CTL_2ND_BASE", + "WF_TOP_SLPPROT_ON_BASE", + "WF_TOP_CFG_BASE", + "WF_MCU_CONFIG_LS_BASE", + "WF_MCU_BUS_CR_BASE", + "WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_BASE", + "WF_TOP_CFG_ON_BASE" +}; + +struct consys_reg_mng_ops g_dev_consys_reg_ops_mt7981 = { + .consys_reg_mng_init = consys_reg_init, + .consys_reg_mng_deinit = consys_reg_deinit, + .consys_reg_mng_check_reable = NULL, + .consys_reg_mng_is_consys_reg = NULL, + .consys_reg_mng_is_bus_hang = NULL, + .consys_reg_mng_dump_bus_status = NULL, + .consys_reg_mng_dump_conninfra_status = NULL, + .consys_reg_mng_dump_cpupcr = NULL, + .consys_reg_mng_is_host_csr = NULL, +}; + +struct consys_base_addr* get_conn_reg_base_addr() +{ + return &conn_reg; +} + +static int consys_reg_init(struct platform_device *pdev) +{ + int ret = -1; + struct device_node *node = NULL; + struct consys_reg_base_addr *base_addr = NULL; + int i = 0; + + node = pdev->dev.of_node; + if (node) { +#if (CFG_REG_LOAD_FROM_DTS_CTRL == 1) + struct resource res; + int flag; + + for (i = 0; i < CONSYS_BASE_ADDR_MAX; i++) { + base_addr = &conn_reg.reg_base_addr[i]; + ret = of_address_to_resource(node, i, &res); + if (ret) { + pr_err("Get Reg Index(%d-%s) failed\n", i, consys_base_addr_index_to_str[i]); + continue; + } + base_addr->phy_addr = res.start; + base_addr->vir_addr = (unsigned long)of_iomap(node, i); + of_get_address(node, i, &(base_addr->size), &flag); +#if 0 + pr_info("Get Index(%d-%s) phy_addr(0x%zx) vir_addr=(0x%zx) size=(0x%zx)\n", + i, consys_base_addr_index_to_str[i], base_addr->phy_addr, + base_addr->vir_addr, base_addr->size); +#endif + } +#else + for (i = 0; i < CONSYS_BASE_ADDR_MAX; i++) { + base_addr = &conn_reg.reg_base_addr[i]; + if (base_addr->vir_addr == 0) + base_addr->vir_addr = (unsigned long)ioremap(base_addr->phy_addr, base_addr->size); + + pr_info("Get Index(%d-%s) phy_addr(0x%zx) vir_addr=(0x%zx) size=(0x%zx)\n", + i, consys_base_addr_index_to_str[i], base_addr->phy_addr, + base_addr->vir_addr, base_addr->size); + } +#endif + } else { + pr_err("[%s] can't find CONSYS compatible node\n", __func__); + return ret; + } + + return 0; +} + +static int consys_reg_deinit(void) +{ + int i = 0; + + for (i = 0; i < CONSYS_BASE_ADDR_MAX; i++) { + if (conn_reg.reg_base_addr[i].vir_addr) { + pr_info("[%d] Unmap %s (0x%zx)\n", i, consys_base_addr_index_to_str[i], + conn_reg.reg_base_addr[i].vir_addr); + iounmap((void __iomem*)conn_reg.reg_base_addr[i].vir_addr); + conn_reg.reg_base_addr[i].vir_addr = 0; + } + } + + return 0; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_emi.c b/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_emi.c new file mode 100644 index 0000000000..c291b0e8c0 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_emi.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include +#include +#include +#include "mt7981_emi.h" +#include "mt7981.h" +#include "mt7981_consys_reg.h" +#include "consys_hw.h" +#include "consys_reg_util.h" +#include "mt7981_pos.h" + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +unsigned int consys_emi_get_fw_emi_size(void) +{ + return 0x100000; +} + +struct consys_platform_emi_ops g_consys_platform_emi_ops_mt7981 = { + .consys_ic_emi_set_region_protection = consys_emi_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .consys_ic_emi_get_fw_emi_size = consys_emi_get_fw_emi_size, +}; + +struct consys_platform_emi_ops* get_consys_platform_emi_ops(void) +{ + return &g_consys_platform_emi_ops_mt7981; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_pmic.c b/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_pmic.c new file mode 100644 index 0000000000..c46da4c845 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_pmic.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include + +#include "consys_hw.h" +#include "consys_reg_util.h" +#include "osal.h" +#include "mt7981_pmic.h" +#include "mt7981_pos.h" +#include "mt7981_consys_reg.h" +#include "mt7981_consys_reg_offset.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +struct consys_platform_pmic_ops g_consys_platform_pmic_ops_mt7981 = { + .consys_pmic_get_from_dts = NULL, + .consys_pmic_common_power_ctrl = NULL, + .consys_pmic_wifi_power_ctrl = NULL, + .consys_pmic_bt_power_ctrl = NULL, + .consys_pmic_gps_power_ctrl = NULL, + .consys_pmic_fm_power_ctrl = NULL, + .consys_pmic_event_notifier = NULL, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +struct consys_platform_pmic_ops* get_consys_platform_pmic_ops(void) +{ + return &g_consys_platform_pmic_ops_mt7981; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_pos.c b/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_pos.c new file mode 100644 index 0000000000..4050b66278 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7981/mt7981_pos.c @@ -0,0 +1,1715 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include +#include "plat_def.h" +#include "consys_reg_util.h" +#include "consys_reg_mng.h" +#include "mt7981_consys_reg.h" +#include "mt7981_consys_reg_offset.h" +#include "mt7981_pos.h" +#include "mt7981.h" +#include "mt7981_emi.h" + + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define MTD_WIFI_NM "Factory" +#define EEPROM_CHIPID_OFFSET 0x0 + +#define EEPROM_BAND0_STREAM_OFFSET 0x190 +#define EEPROM_BAND0_STREAM_TX_MASK 0x7 +#define EEPROM_BAND0_STREAM_TX_BIT_OFFSET 0 +#define EEPROM_BAND0_STREAM_RX_MASK 0x7 +#define EEPROM_BAND0_STREAM_RX_BIT_OFFSET 3 + +#define _TO_STR(_x) #_x +#define TO_STR(_x) _TO_STR(_x) +#define RED(_text) "\033[1;31m"_text"\033[0m" +#define GRN(_text) "\033[1;32m"_text"\033[0m" + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +bool one_adie_dbdc = false; +bool adie_7976 = false; +unsigned int adie_cfg_type = ADIE_TYPE_NONE; + +struct spi_op { + unsigned int busy_cr; + unsigned int polling_bit; + unsigned int addr_cr; + unsigned int read_addr_format; + unsigned int write_addr_format; + unsigned int write_data_cr; + unsigned int read_data_cr; + unsigned int read_data_mask; +}; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +const static char* g_spi_system_name[SYS_SPI_MAX] = { + "SYS_SPI_WF1", + "SYS_SPI_WF", + "SYS_SPI_BT", + "SYS_SPI_FM", + "SYS_SPI_GPS", + "SYS_SPI_TOP", + "SYS_SPI_WF2", + "SYS_SPI_WF3", +}; + +static const struct spi_op spi_op_array[SYS_SPI_MAX] = { + /* SYS_SPI_WF1 */ + { + SPI_STA, 1, SPI_WF_ADDR, 0x00001000, 0x00000000, + SPI_WF_WDAT, SPI_WF_RDAT, 0xFFFFFFFF + }, + /* SYS_SPI_WF */ + { + SPI_STA, 1, SPI_WF_ADDR, 0x00003000, 0x00002000, + SPI_WF_WDAT, SPI_WF_RDAT, 0xFFFFFFFF + }, + /* SYS_SPI_BT */ + { + SPI_STA, 2, SPI_BT_ADDR, 0x00005000, 0x00004000, + SPI_BT_WDAT, SPI_BT_RDAT, 0xFFFFFFFF + }, + /* SYS_SPI_FM */ + { + SPI_STA, 3, SPI_FM_ADDR, 0x00007000, 0x00006000, + SPI_FM_WDAT, SPI_FM_RDAT, 0x0000FFFF + }, + /* SYS_SPI_GPS */ + { + SPI_STA, 4, SPI_GPS_ADDR, 0x00009000, 0x00008000, + SPI_GPS_WDAT, SPI_GPS_RDAT, 0x0000FFFF + }, + /* SYS_SPI_TOP */ + { + SPI_STA, 5, SPI_TOP_ADDR, 0x0000B000, 0x0000A000, + SPI_TOP_WDAT, SPI_TOP_RDAT, 0xFFFFFFFF + }, + /* SYS_SPI_WF2 */ + { + SPI_STA, 1, SPI_WF_ADDR, 0x0000D000, 0x0000C000, + SPI_WF_WDAT, SPI_WF_RDAT, 0xFFFFFFFF + }, + /* SYS_SPI_WF3 */ + { + SPI_STA, 1, SPI_WF_ADDR, 0x0000F000, 0x0000E000, + SPI_WF_WDAT, SPI_WF_RDAT, 0xFFFFFFFF + }, +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +bool _is_flash_content_valid(void) +{ + unsigned short eeFlashId = 0; + + FlashRead(MTD_WIFI_NM, (unsigned char*)&eeFlashId, EEPROM_CHIPID_OFFSET, sizeof(eeFlashId)); + + if (eeFlashId == consys_soc_chipid_get()) + return true; + else + return false; +} + +int _consys_check_adie_cfg(void) +{ + int ret = 0; + unsigned int hw_adie_type = 0; + unsigned int i = 0; + bool found = false; + + for (i = 0; i < AIDE_NUM_MAX; i++) { + if (conn_hw_env[i].valid) { + hw_adie_type = conn_hw_env[i].adie_id; + found = true; + break; + } + } + + if (found) { + printk(GRN("Adie Type: 0x%x"), hw_adie_type); + } else { + printk(RED("No Adie found!!!")); + ret = -1; + } + + return ret; +} + +int consys_plt_hw_init(void) +{ + /* Cheetah only has a-die 7976 and one-adie-dbdc */ + adie_7976 = true; + one_adie_dbdc = true; + adie_cfg_type = ADIE_TYPE_ONE; + pr_info("adie_cfg_type = %d, one_adie_dbdc = %d\n", adie_cfg_type, one_adie_dbdc); + return 0; +} + +int consys_xtal_ctrl_fast_mode(void) +{ + /* Setting fast mode to xtal control */ + CONSYS_SET_BIT(REG_TOP_MISC_ADDR + CONNSYS_MISC, (0x1 << 3)); + return 0; +} + +int consys_sw_reset_ctrl(bool bassert) +{ + /* Release CONNSYS software reset */ + if (bassert) { + CONSYS_REG_WRITE_MASK( + REG_TOP_RGU_ADDR + TOP_RGU_WDT_SWSYSRST, + 0x88800000, 0xff800000); + } else { + /* de-assert CONNSYS S/W reset */ + CONSYS_REG_WRITE_MASK( + REG_TOP_RGU_ADDR + TOP_RGU_WDT_SWSYSRST, + 0x88000000, 0xff800000); + } + + return 0; +} + +void consys_set_if_pinmux(bool enable) +{ + if (enable) { + /* One_Adie_DB + set pinmux for the interface between D-die and A-die (Aux1) + PAD_WF0_TOP_CLK(GPIO43) 0x0350[14:12] + PAD_WF0_TOP_DATA(GPIO44) 0x0350[18:16] + PAD_WF0_HB1(GPIO45) 0x0350[22:20] + PAD_WF0_HB2(GPIO46) 0x0350[26:24] + PAD_WF0_HB3(GPIO47) 0x0350[30:28] + PAD_WF0_HB4(GPIO48) 0x0360[2:0] + PAD_WF0_HB0(GPIO49) 0x0360[6:4] + PAD_WF0_HB0_B(GPIO50) 0x0360[10:8] + PAD_WF0_HB5(GPIO51) 0x0360[14:12] + PAD_WF0_HB6(GPIO52) 0x0360[18:16] + PAD_WF0_HB7(GPIO53) 0x0360[22:20] + PAD_WF0_HB8(GPIO54) 0x0360[26:24] + PAD_WF0_HB9(GPIO55) 0x0360[30:28] + PAD_WF0_HB10(GPIO56) 0x0370[2:0] + */ + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE5, 0x11111000, 0x77777000); + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE6, 0x11111111, 0x77777777); + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE7, 0x00000001, 0x00000007); + + /* Set pinmux driving to 4mA */ + CONSYS_REG_WRITE_MASK(REG_IOCFG_TM_ADDR + IOCFG_TM_DRV_CFG0, 0x49249, 0x1FFFFF); + CONSYS_REG_WRITE_MASK(REG_IOCFG_LT_ADDR + IOCFG_LT_DRV_CFG0, 0x1249240, 0x7FFFFC0); + } +} + +int consys_tx_rx_bus_slp_prot_ctrl(bool enable) +{ + int check; + + if (enable) { + /* conn2ap/ap2conn slpprot disable */ + /* Turn off AP2CONN AHB RX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, 0x0, 0x10000); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, + 24, 0x0, 100, 500, check); + if (check != 0) + pr_err("Polling AP2CONN AHB RX bus sleep protect turn off fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT)); + + /* Turn off AP2CONN AHB TX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, 0x0, 0x1); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, + 4, 0x0, 100, 500, check); + if (check != 0) + pr_err("Polling AP2CONN AHB TX bus sleep protect turn off fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT)); + + /* Turn off CONN2AP AXI RX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, 0x0, 0x10000); + /* Turn off CONN2AP AXI TX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, 0x0, 0x1); + + /* Wait 900us (apply this for CONNSYS XO clock ready) */ + udelay(900); + } else { + /* Turn on AP2CONN AHB TX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, 0x1, 0x1); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, + 4, 0x1, 100, 500, check); + if (check != 1) + pr_err("Polling AP2CONN AHB TX bus sleep protect turn on fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT)); + + /* Turn on AP2CONN AHB RX bus sleep protec */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, 0x1, 0x10000); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, + 24, 0x1, 100, 500, check); + if (check !=1) + pr_err("Polling AP2CONN AHB RX bus sleep protect turn on fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT)); + + /* Turn on CONN2AP AXI TX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, 0x1, 0x1); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, + 4, 0x1, 100, 500, check); + if (check != 1) + pr_err("Polling CONN2AP AXI TX bus sleep protect turn on fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT)); + + /* Turn on CONN2AP AXI RX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, 0x1, 0x10000); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, + 24, 0x1, 100, 500, check); + if (check != 1) + pr_err("Polling CONN2AP AXI RX bus sleep protect turn on fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT)); + + /* wait 1us*/ + udelay(1); + } + + return 0; +} + +int _consys_polling_chipid_int(unsigned int retry, unsigned int sleep_ms) +{ + unsigned int count = retry + 1; + unsigned int consys_hw_ver = consys_get_hw_ver(); + unsigned int hw_ver = 0; + + while (--count > 0) { + hw_ver = CONSYS_REG_READ(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_CFG_IP_VERSION); + if ((hw_ver >= consys_hw_ver) && (hw_ver != 0xdeadfeed)) + break; + msleep(sleep_ms); + } + + if (count == 0) { + pr_err("Read CONNSYS HW IP version fail. Expect 0x%x but get 0x%x\n", consys_hw_ver, hw_ver); + return -1; + } else { + pr_info("Read CONNSYS HW IP version successfully! (0x%08x)\n", hw_ver); + } + + return 0; +} + +int consys_polling_chipid(void) +{ + return _consys_polling_chipid_int(10, 1); +} + +int consys_bus_clock_ctrl(enum consys_drv_type drv_type, unsigned int bus_clock) +{ + /* Cheetah doesn't need to do anything according to DE's excel */ + return 0; +} + +int consys_emi_set_remapping_reg(void) +{ + struct consys_emi_addr_info *addr_info = emi_mng_get_phy_addr(); + + /* 0x1806_01C4[19:0], ap_emi_base[19:0] = TBD (related to emi) + 0x1806_01D4[19:0], wf_ap_peri_base[19:0] = 0x0_1100 (un-related to emi) + */ + if (addr_info->emi_ap_phy_base != 0) + CONSYS_REG_WRITE_OFFSET_RANGE(REG_CONN_HOST_CSR_TOP_ADDR + CONN2AP_REMAP_MCU_EMI, + addr_info->emi_ap_phy_base, 0, 16, 20); + + CONSYS_REG_WRITE_OFFSET_RANGE(REG_CONN_HOST_CSR_TOP_ADDR + CONN2AP_REMAP_WF_PERI, + 0x300D0000, 0, 16, 20); + + CONSYS_REG_WRITE_OFFSET_RANGE(REG_CONN_HOST_CSR_TOP_ADDR + CONN2AP_RSVD_PERI_REGION1, + 0x11F20000, 0, 16, 20); + + return 0; +} + +int consys_emi_set_region_protection(void) +{ + struct consys_emi_addr_info *addr_info = emi_mng_get_phy_addr(); + + /* set infra top emi address range */ + if (addr_info->emi_ap_phy_base != 0) { + CONSYS_REG_WRITE(REG_CONN_INFRA_BUS_CR_ADDR + CONN2AP_EMI_PATH_ADDR_START, + addr_info->emi_ap_phy_base); + + if (addr_info->emi_ap_phy_size != 0) + CONSYS_REG_WRITE(REG_CONN_INFRA_BUS_CR_ADDR + CONN2AP_EMI_PATH_ADDR_END, + addr_info->emi_ap_phy_base + addr_info->emi_ap_phy_size); + } + + return 0; +} + +int connsys_d_die_cfg(void) +{ + unsigned int efuse; + + efuse = CONSYS_REG_READ(REG_CONN_INFRA_CFG_ADDR + EFUSE); + pr_info("D-die efuse: 0x%08x\n", efuse); + + return 0; +} + +int connsys_conninfra_sysram_hw_ctrl(void) +{ + /* conn_infra sysram hw control setting -> disable hw power down */ + CONSYS_REG_WRITE(REG_CONN_INFRA_RGU_ADDR + SYSRAM_HWCTL_PDN, 0x0); + + /* conn_infra sysram hw control setting -> enable hw sleep */ + CONSYS_REG_WRITE(REG_CONN_INFRA_RGU_ADDR + SYSRAM_HWCTL_SLP, 0x1); + + return 0; +} + +int connsys_spi_master_cfg(void) +{ + /* wt_slp CR for A-die ck_en/wake_en control */ + /* + RFSPI #0 RFSPI #1 + WF_CK_ADDR 0x18005070[11:0] 0x18085070[11:0] 0xA04 + WF_B1_CK_ADDR 0x18005070[27:16] 0x18085070[27:16] 0xAF4 + WF_WAKE_ADDR 0x18005074[11:0] 0x18085074[11:0] 0x090 + WF_B1_WAKE_ADDR 0x18005074[27:16] 0x18085074[27:16] 0x0A0 + WF_ZPS_ADDR 0x18005078[11:0] 0x18085078[11:0] 0x08C + WF_B1_ZPS_ADDR 0x18005078[27:16] 0x18085078[27:16] 0x09C + TOP_CK_ADDR 0x18005084[11:0] 0x18085084[11:0] 0xA00 + WF_B0_CMD_ADDR 0x1800508c[11:0] 0x1808508c[11:0] 0x0F0 + WF_B1_CMD_ADDR 0x18005090[11:0] 0x18085090[11:0] 0x0F4 + */ + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_CK_ADDR, 0xAF40A04, 0xFFF0FFF); + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_WAKE_ADDR, 0x0A00090, 0xFFF0FFF); + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_ZPS_ADDR, 0x09C008C, 0xFFF0FFF); + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_TOP_CK_ADDR, 0xA00, 0xFFF); + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_B0_CMD_ADDR, 0x0F0, 0xFFF); + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_B1_CMD_ADDR, 0x0F4, 0xFFF); + + /* Cheetah doesn't need to configure RFSPI#1 */ + + return 0; +} + +static int consys_spi_read_nolock(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data) +{ + int check = 0; + unsigned long rf_spi_addr = 0; + const struct spi_op *op = NULL; + unsigned char adie_idx = ((subsystem & 0xF0) >> 4); //0: one adie, 1: two adie + unsigned char subsystem_idx = (subsystem & 0xF); + + if (!data) { + pr_err("invalid data ptr\n"); + return CONNINFRA_SPI_OP_FAIL; + } + + op = &spi_op_array[subsystem_idx]; + if (adie_idx != 0) + rf_spi_addr = REG_INST2_CONN_RF_SPI_MST_REG_ADDR; + else + rf_spi_addr = REG_CONN_RF_SPI_MST_REG_ADDR; + + /* Read action: + * 1. Polling busy_cr[polling_bit] should be 0 + * 2. Write addr_cr with data being {read_addr_format | addr[11:0]} + * 3. Trigger SPI by writing write_data_cr as 0 + * 4. Polling busy_cr[polling_bit] as 0 + * 5. Read data_cr[data_mask] + */ + + CONSYS_REG_BIT_POLLING(rf_spi_addr + op->busy_cr, op->polling_bit, 0, 100, 500, check); + if (check != 0) { + pr_err("[%d][STEP1] polling 0x%08lx bit %d fail. Value=0x%08x\n", + subsystem, rf_spi_addr + op->busy_cr, op->polling_bit, + CONSYS_REG_READ(rf_spi_addr + op->busy_cr)); + return CONNINFRA_SPI_OP_FAIL; + } + + CONSYS_REG_WRITE(rf_spi_addr + op->addr_cr, (op->read_addr_format | addr)); + CONSYS_REG_WRITE(rf_spi_addr + op->write_data_cr, 0); + + CONSYS_REG_BIT_POLLING(rf_spi_addr + op->busy_cr, op->polling_bit, 0, 100, 500, check); + if (check != 0) { + pr_err("[%d][STEP4] polling 0x%08lx bit %d fail. Value=0x%08x\n", + subsystem, rf_spi_addr + op->busy_cr, + op->polling_bit, CONSYS_REG_READ(rf_spi_addr + op->busy_cr)); + return CONNINFRA_SPI_OP_FAIL; + } + + check = CONSYS_REG_READ_BIT(rf_spi_addr + op->read_data_cr, op->read_data_mask); + *data = check; + + return 0; +} + +static int consys_spi_write_nolock(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data) +{ + int check = 0; + unsigned long rf_spi_addr = 0; + const struct spi_op *op = NULL; + unsigned char adie_idx = ((subsystem & 0xF0) >> 4); //0: one adie, 1: two adie + unsigned char subsystem_idx = (subsystem & 0xF); + + op = &spi_op_array[subsystem_idx]; + if (adie_idx != 0) + rf_spi_addr = REG_INST2_CONN_RF_SPI_MST_REG_ADDR; + else + rf_spi_addr = REG_CONN_RF_SPI_MST_REG_ADDR; + + /* Write action: + * 1. Wait busy_cr[polling_bit] as 0 + * 2. Write addr_cr with data being {write_addr_format | addr[11:0] + * 3. Write write_data_cr ad data + * 4. Wait busy_cr[polling_bit] as 0 + */ + + CONSYS_REG_BIT_POLLING(rf_spi_addr + op->busy_cr, op->polling_bit, 0, 100, 500, check); + if (check != 0) { + pr_err("[%d][STEP1] polling 0x%08lx bit %d fail. Value=0x%08x\n", + subsystem, rf_spi_addr + op->busy_cr, + op->polling_bit, CONSYS_REG_READ(rf_spi_addr + op->busy_cr)); + return CONNINFRA_SPI_OP_FAIL; + } + + CONSYS_REG_WRITE(rf_spi_addr + op->addr_cr, (op->write_addr_format | addr)); + CONSYS_REG_WRITE(rf_spi_addr + op->write_data_cr, data); + + check = 0; + CONSYS_REG_BIT_POLLING(rf_spi_addr + op->busy_cr, op->polling_bit, 0, 100, 500, check); + if (check != 0) { + pr_err("[%d][STEP4] polling 0x%08lx bit %d fail. Value=0x%08x\n", + subsystem, rf_spi_addr + op->busy_cr, + op->polling_bit, CONSYS_REG_READ(rf_spi_addr + op->busy_cr)); + return CONNINFRA_SPI_OP_FAIL; + } + + pr_info("addr=0x%04x, val=0x%08x\n", addr, data); + + return 0; +} + +static int consys_sema_acquire(enum conn_semaphore_type index) +{ + if (CONSYS_REG_READ_BIT((REG_CONN_SEMAPHORE_ADDR + CONN_SEMA00_M2_OWN_STA + index*4), 0x1) == 0x1) { + return CONN_SEMA_GET_SUCCESS; + } else { + return CONN_SEMA_GET_FAIL; + } +} + +int consys_sema_acquire_timeout(unsigned int index, unsigned int usec) +{ + int i; + + if (index >= CONN_SEMA_NUM_MAX) { + pr_err("wrong index: %d\n", index); + return CONN_SEMA_GET_FAIL; + } + + for (i = 0; i < usec; i++) { + if (consys_sema_acquire(index) == CONN_SEMA_GET_SUCCESS) { + return CONN_SEMA_GET_SUCCESS; + } + udelay(1); + } + pr_err("Get semaphore 0x%x timeout, dump status:\n", index); + pr_err("M0:[0x%x] M1:[0x%x] M2:[0x%x] M3:[0x%x] M4:[0x%x] M5:[0x%x] M6:[0x%x] M7:[0x%x]\n", + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M0_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M1_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M2_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M3_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M4_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M5_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M6_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M7_STA_REP)); + + return CONN_SEMA_GET_FAIL; +} + +void consys_sema_release(unsigned int index) +{ + if (index >= CONN_SEMA_NUM_MAX) { + pr_err("wrong index: %d\n", index); + return; + } + + CONSYS_REG_WRITE((REG_CONN_SEMAPHORE_ADDR + CONN_SEMA00_M2_OWN_REL + index*4), 0x1); +} + +int consys_spi_read(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data) +{ + int ret; + + /* Get semaphore before read */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("[SPI READ] Require semaphore fail\n"); + return CONNINFRA_SPI_OP_FAIL; + } + + ret = consys_spi_read_nolock(subsystem, addr, data); + + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return ret; +} + +int consys_spi_write(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data) +{ + int ret; + + /* Get semaphore before read */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("[SPI WRITE] Require semaphore fail\n"); + return CONNINFRA_SPI_OP_FAIL; + } + + ret = consys_spi_write_nolock(subsystem, addr, data); + + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + return ret; +} + +static void consys_spi_write_offset_range_nolock( + enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int value, + unsigned int reg_offset, unsigned int value_offset, unsigned int size) +{ + unsigned int data = 0, data2; + unsigned int reg_mask; + int ret; + + pr_info("[%s] addr=0x%04x value=0x%08x reg_offset=%d value_offset=%d size=%d\n", + g_spi_system_name[subsystem], addr, value, reg_offset, value_offset, size); + + value = (value >> value_offset); + value = GET_BIT_RANGE(value, size, 0); + value = (value << reg_offset); + ret = consys_spi_read_nolock(subsystem, addr, &data); + if (ret) { + pr_err("[%s] Get 0x%08x error, ret=%d\n", + g_spi_system_name[subsystem], addr, ret); + return; + } + + reg_mask = GENMASK(reg_offset + size - 1, reg_offset); + data2 = data & (~reg_mask); + data2 = (data2 | value); + consys_spi_write_nolock(subsystem, addr, data2); + + pr_info("[%s] Write CR:0x%08x from 0x%08x to 0x%08x\n", + g_spi_system_name[subsystem], addr, data, data2); +} + +int consys_spi_write_offset_range( + enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int value, + unsigned int reg_offset, unsigned int value_offset, unsigned int size) +{ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("[SPI READ] Require semaphore fail\n"); + return CONNINFRA_SPI_OP_FAIL; + } + consys_spi_write_offset_range_nolock(subsystem, addr, value, reg_offset, value_offset, size); + + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return 0; +} + +/***************************************************************************** +* FUNCTION +* connsys_a_die_efuse_read +* DESCRIPTION +* Read a-die efuse +* PARAMETERS +* efuse_addr: read address +* RETURNS +* int +* 0: fail, efuse is invalid +* 1: success, efuse is valid +*****************************************************************************/ +static int connsys_a_die_efuse_read_nolock( + enum sys_spi_subsystem subsystem, unsigned int efuse_ctrl, unsigned int efuse_addr, + unsigned int *data0, unsigned int *data1, unsigned int *data2, unsigned int *data3) +{ + int ret = 0; + int retry = 0; + int ret0, ret1, ret2, ret3; + unsigned int efuse_block_sel; + + if (data0 == NULL || data1 == NULL || data2 == NULL || data3 == NULL) { + pr_err("invalid parameter (%p, %p, %p, %p)\n", + data0, data1, data2, data3); + return 0; + } + + switch (efuse_ctrl) { + case ATOP_EFUSE_CTRL_1: + efuse_block_sel = 0x1; + break; + + case ATOP_EFUSE_CTRL_2: + efuse_block_sel = 0x2; + break; + + case ATOP_EFUSE_CTRL_3: + efuse_block_sel = 0x4; + break; + + case ATOP_EFUSE_CTRL_4: + efuse_block_sel = 0x8; + break; + + default: + pr_err("Not support for efuse block No. = %d\n", efuse_ctrl); + return 0; + break; + } + + /* select Efuse block */ + consys_spi_write_nolock(subsystem, ATOP_RG_EFUSE_CFG5, efuse_block_sel); + + /* Efuse control clear, clear Status /trigger + * Address: ATOP EFUSE_CTRL_write_efsrom_kick_and_read_kick_busy_flag (0x108[30]) + * Data: 1'b0 + * Action: TOPSPI_WR + */ + consys_spi_read_nolock(subsystem, efuse_ctrl, &ret); + ret &= ~(0x1 << 30); + consys_spi_write_nolock(subsystem, efuse_ctrl, ret); + + /* Efuse Read 1st 16byte + * Address: + * ATOP EFUSE_CTRL_efsrom_mode (0x108[7:6]) = 2'b00 + * ATOP EFUSE_CTRL_efsrom_ain (0x108[25:16]) = efuse_addr (0) + * ATOP EFUSE_CTRL_write_efsrom_kick_and_read_kick_busy_flag (0x108[30]) = 1'b1 + * Action: TOPSPI_WR + */ + consys_spi_read_nolock(subsystem, efuse_ctrl, &ret); + ret &= ~(0x43FF00C0); + ret |= (0x1 << 30); + ret |= ((efuse_addr << 16) & 0x3FF0000); + consys_spi_write_nolock(subsystem, efuse_ctrl, ret); + + /* Polling EFUSE busy = low + * (each polling interval is "30us" and polling timeout is 2ms) + * Address: + * ATOP EFUSE_CTRL_write_efsrom_kick_and_read_kick_busy_flag (0x108[30]) = 1'b0 + * Action: TOPSPI_Polling + */ + consys_spi_read_nolock(subsystem, efuse_ctrl, &ret); + while ((ret & (0x1 << 30)) != 0 && retry < 70) { + retry++; + udelay(30); + consys_spi_read_nolock(subsystem, efuse_ctrl, &ret); + } + if ((ret & (0x1 << 30)) != 0) { + pr_err("EFUSE busy, retry failed(%d)\n", retry); + } + + /* Check efuse_valid & return + * Address: ATOP EFUSE_CTRL_csri_efsrom_dout_vld_sync_1_ (0x108[29]) + * Action: TOPSPI_RD + */ + /* if (efuse_valid == 1'b1) + * Read Efuse Data to global var + */ + consys_spi_read_nolock(subsystem, efuse_ctrl, &ret); + if (((ret & (0x1 << 29)) >> 29) == 1) { + ret0 = consys_spi_read_nolock(subsystem, ATOP_EFUSE_RDATA0, data0); + ret1 = consys_spi_read_nolock(subsystem, ATOP_EFUSE_RDATA1, data1); + ret2 = consys_spi_read_nolock(subsystem, ATOP_EFUSE_RDATA2, data2); + ret3 = consys_spi_read_nolock(subsystem, ATOP_EFUSE_RDATA3, data3); + + pr_info("efuse = [0x%08x, 0x%08x, 0x%08x, 0x%08x]\n", *data0, *data1, *data2, *data3); + if (ret0 || ret1 || ret2 || ret3) + pr_err("efuse read error: [%d, %d, %d, %d]\n", ret0, ret1, ret2, ret3); + ret = 1; + } else { + pr_err("EFUSE is invalid\n"); + ret = 0; + } + + return ret; +} + +static int _connsys_a_die_thermal_cal(enum sys_spi_subsystem subsystem) +{ + int efuse_valid = 0; + unsigned int efuse0 = 0, efuse1 = 0, efuse2 = 0, efuse3 = 0; + + /* thernal efuse data in 7976&7975 in EFUSE2 */ + efuse_valid = connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_THADC_ANALOG, + &efuse0, &efuse1, &efuse2, &efuse3); + //if (efuse_valid) { + if ((efuse0 & (0x1 << 7))) { + consys_spi_write_offset_range_nolock(subsystem, ATOP_RG_TOP_THADC_BG, efuse0, 12, 3, 4); + consys_spi_write_offset_range_nolock(subsystem, ATOP_RG_TOP_THADC_00, efuse0, 23, 0, 3); + } + //} + + efuse_valid = connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_THADC_SLOP, + &efuse0, &efuse1, &efuse2, &efuse3); + //if (efuse_valid) { + if((efuse0 & (0x1 << 7))) { + consys_spi_write_offset_range_nolock(subsystem, ATOP_RG_TOP_THADC_00, efuse0, 26, 5, 2); + } + //} + + return 0; +} + +static int _connsys_a_die_xtal_trim_7976(enum sys_spi_subsystem subsystem) +{ + unsigned int efuse0 = 0, efuse1 = 0, efuse2 = 0, efuse3 = 0; + int c1c2_trim_result_ax_80m = 0, c1c2_trim_result_ax_40m = 0; + unsigned int cbtop_strap_rdata = 0, xtal_strap_mode = 0, adie_rdata = 0, value = 0; + + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_XTAL_TRIM_FLOW, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 < 1))) { + /* C1C2 80M AX */ + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_XTAL_CR_C1_SEL_AXM_80M_OSC, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 < 7)) == 0) { + c1c2_trim_result_ax_80m = 64; + } else { + c1c2_trim_result_ax_80m = (efuse0 & 0x7F); + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_XTAL_CR_C1_SEL_AXM_TRIM1_80M_OSC, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 < 7)) == 1) { + if ((efuse0 & (0x1 < 6)) == 0) { + c1c2_trim_result_ax_80m += c1c2_trim_result_ax_80m + (efuse0 & 0x3F); + } else { + c1c2_trim_result_ax_80m = c1c2_trim_result_ax_80m - (efuse0 & 0x3F); + } + + if (c1c2_trim_result_ax_80m > 127) + c1c2_trim_result_ax_80m = 127; + else if (c1c2_trim_result_ax_80m < 0) + c1c2_trim_result_ax_80m = 0; + } + } + + /* C1C2 40M AX */ + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_XTAL_CR_C1_SEL_AXM_40M_OSC, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 < 7)) == 0) { + c1c2_trim_result_ax_40m = 64; + } else { + c1c2_trim_result_ax_40m = (efuse0 & 0x7F); + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_XTAL_CR_C1_SEL_AXM_TRIM1_40M_OSC, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 < 7)) == 1) { + if ((efuse0 & (0x1 < 6)) == 0) { + c1c2_trim_result_ax_40m += c1c2_trim_result_ax_40m + (efuse0 & 0x3F); + } else { + c1c2_trim_result_ax_40m = c1c2_trim_result_ax_40m - (efuse0 & 0x3F); + } + + if (c1c2_trim_result_ax_40m > 127) + c1c2_trim_result_ax_40m = 127; + else if (c1c2_trim_result_ax_40m < 0) + c1c2_trim_result_ax_40m = 0; + } + } + + /* Update trim value to C1 and C2 */ + consys_spi_read_nolock(subsystem, ATOP_RG_STRAP_PIN_IN, &cbtop_strap_rdata); + xtal_strap_mode = ((cbtop_strap_rdata & 0x70) >> 4); + if ((xtal_strap_mode == 0x0) || (xtal_strap_mode == 0x2)) { //80m osc + /* C1 */ + consys_spi_read_nolock(subsystem, 0x654, &adie_rdata); + value = (adie_rdata & 0xFFFFFF) | ((c1c2_trim_result_ax_80m & 0xFF) << 24); + consys_spi_write_nolock(subsystem, 0x654, value); + + /* C2 */ + consys_spi_read_nolock(subsystem, 0x658, &adie_rdata); + value = (adie_rdata & 0xFFFFFF) | ((c1c2_trim_result_ax_80m & 0xFF) << 24); + consys_spi_write_nolock(subsystem, 0x658, value); + } else if ((xtal_strap_mode == 0x3) || (xtal_strap_mode == 0x4) || (xtal_strap_mode == 0x6)) { //40m osc + /* C1 */ + consys_spi_read_nolock(subsystem, 0x654, &adie_rdata); + value = (adie_rdata & 0xFF00FFFF) | ((c1c2_trim_result_ax_40m & 0xFF) << 16); + consys_spi_write_nolock(subsystem, 0x654, value); + + /* C2 */ + consys_spi_read_nolock(subsystem, 0x658, &adie_rdata); + value = (adie_rdata & 0xFF00FFFF) | ((c1c2_trim_result_ax_40m & 0xFF) << 16); + consys_spi_write_nolock(subsystem, 0x658, value); + } + } + + return 0; +} + +static int _connsys_a_die_sw_cntl(enum sys_spi_subsystem subsystem, unsigned char adie_idx) +{ + if (conn_hw_env[adie_idx].valid && (conn_hw_env[adie_idx].adie_id == 0x7976)) { + if ((conn_hw_env[adie_idx].adie_hw_version == 0x8A00) + || (conn_hw_env[adie_idx].adie_hw_version == 0x8A10) + || (conn_hw_env[adie_idx].adie_hw_version == 0x8B00)){ + consys_spi_write_nolock(subsystem, ATOP_RG_TOP_THADC_00, 0x4A563B00); + consys_spi_write_nolock(subsystem, ATOP_RG_XO_01, 0x1D59080F); + consys_spi_write_nolock(subsystem, ATOP_RG_XO_03, 0x34C00FE0); + } else { + consys_spi_write_nolock(subsystem, ATOP_RG_TOP_THADC_00, 0x4A563B00); + consys_spi_write_nolock(subsystem, ATOP_RG_XO_01, 0x1959C80F); + consys_spi_write_nolock(subsystem, ATOP_RG_XO_03, 0x34D00FE0); + } + } + + return 0; +} + +int _connsys_a_die_cfg_7976(unsigned char adie_idx) +{ + int check; + unsigned int adie_chip_id = 0x0; + unsigned char subsystem = 0; + + if (adie_idx == 1) + subsystem = SYS_SPI_2ND_ADIE_TOP; + else + subsystem = SYS_SPI_TOP; + + /* release D Die to A Die Digital reset_b */ + if (adie_idx == 1) + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x4); + else + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x1); + + /* Get semaphore once */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("Require semaphore fail\n"); + return -1; + } + + /* read a-die ID */ + check = consys_spi_read_nolock(subsystem, ATOP_CHIP_ID, &adie_chip_id); + if (check) { + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + pr_err("Get ATOP_CHIP_ID fail, check=%d\n", check); + return -1; + } + + if (adie_idx < AIDE_NUM_MAX && ((adie_chip_id & 0xFFFF0000) != 0)) { + conn_hw_env[adie_idx].valid = true; + conn_hw_env[adie_idx].adie_hw_version = (adie_chip_id & 0xFFFF); + conn_hw_env[adie_idx].adie_id = ((adie_chip_id & 0xFFFF0000) >> 16); + conn_hw_env[adie_idx].is_rc_mode = 0; + + pr_info("adie_idx[%d], A-die CHIP ID = 0x%x, HW Version = 0x%x\n", + adie_idx, conn_hw_env[adie_idx].adie_id, conn_hw_env[adie_idx].adie_hw_version); + } + + /* enable TOPDIG CK */ + check = consys_spi_write_nolock(subsystem, ATOP_TOP_CLK_EN, 0xFFFFFFFF); + + /* config WRI CK select */ + if (one_adie_dbdc) + check = consys_spi_write_nolock(subsystem, ATOP_RG_WRI_CK_SELECT, 0x1C); + + /* Thermal Cal (TOP) */ + _connsys_a_die_thermal_cal(subsystem); + + /* XTAL TRIM */ + _connsys_a_die_xtal_trim_7976(subsystem); + + /* SW control part */ + _connsys_a_die_sw_cntl(subsystem, adie_idx); + + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return 0; +} + +static int _connsys_a_die_xtal_trim_7975(enum sys_spi_subsystem subsystem) +{ + unsigned int efuse0 = 0, efuse1 = 0, efuse2 = 0, efuse3 = 0; + unsigned int trim_result = 0, value = 0; + int ret = 0; + + ret = connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_7975_XTAL_TRIM_FLOW, + &efuse0, &efuse1, &efuse2, &efuse3); + if (((efuse0 & 0x1) == 0) || (ret == 0)) + return 0; + + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_7975_XTAL_CALIBRATION, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 << 7))) { + trim_result = (efuse0 & 0x7F); + trim_result = (trim_result & 0x7F); + } + + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_7975_XTAL_TRIM2_COMPENSATION, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 << 7))){ + if ((efuse0 & (0x1 << 6))) + trim_result -= (efuse0 & 0x3F); + else + trim_result += (efuse0 & 0x3F); + trim_result = (trim_result & 0x7F); + } + + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_7975_XTAL_TRIM3_COMPENSATION, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 << 7))){ + if ((efuse0 & (0x1 << 6))) + trim_result -= (efuse0 & 0x3F); + else + trim_result += (efuse0 & 0x3F); + trim_result = (trim_result & 0x7F); + } + + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_7975_XTAL_TRIM4_COMPENSATION, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 << 7))){ + if ((efuse0 & (0x1 << 6))) + trim_result -= (efuse0 & 0x3F); + else + trim_result += (efuse0 & 0x3F); + trim_result = (trim_result & 0x7F); + } + + /* Update Trim Value to C1 and C2*/ + /* Step 1 */ + consys_spi_read_nolock(subsystem, ATOP_7975_CR_C1_C2_A94, &value); + value = ((value & 0xf8080fff) | ((trim_result << 20) | (trim_result << 12))); + consys_spi_write_nolock(subsystem, ATOP_7975_CR_C1_C2_A94, value); + + /* Step 2 */ + consys_spi_read_nolock(subsystem, ATOP_7975_CR_C1_C2_A18, &value); + if(value & (1<<29)){ + consys_spi_read_nolock(subsystem, ATOP_7975_CR_C1_C2_A84, &value); + value = (value & 0x7fffffff); + consys_spi_write_nolock(subsystem, ATOP_7975_CR_C1_C2_A84, value); + } + + /* Step 3 */ + consys_spi_read_nolock(subsystem, ATOP_7975_CR_C1_C2_AA4, &value); + value = ((value & 0xfffeffff) | 0x10000); + consys_spi_write_nolock(subsystem, ATOP_7975_CR_C1_C2_AA4, value); + + return 0; +} + + +static int _connsys_a_die_form_patch_7975(enum sys_spi_subsystem subsystem) +{ + pr_info("Form 7975 adie Patch\n"); + + /* disable CAL LDO and fine tune RFDIG LDO, 20191218 */ + consys_spi_write_nolock(subsystem, 0x348, 0x00000002); + + /* disable CAL LDO and fine tune RFDIG LDO, 20191218 */ + consys_spi_write_nolock(subsystem, 0x378, 0x00000002); + + /* disable CAL LDO and fine tune RFDIG LDO, 20191218 */ + consys_spi_write_nolock(subsystem, 0x3A8, 0x00000002); + + /* disable CAL LDO and fine tune RFDIG LDO, 20191218 */ + consys_spi_write_nolock(subsystem, 0x3D8, 0x00000002); + + /* set CKA driving and filter */ + consys_spi_write_nolock(subsystem, 0xA1C, 0x30000AAA); + + /* set CKB LDO to 1.4V */ + consys_spi_write_nolock(subsystem, 0xA84, 0x8470008A); + + /* turn on SX0 LTBUF */ + consys_spi_write_nolock(subsystem, 0x074, 0x00000007); + + /* CK_BUF_SW_EN=1 (all buf in manual mode.) */ + consys_spi_write_nolock(subsystem, 0xAA4, 0x01001FC0); + + /* BT mode/WF normal mode 32'h=00000005 */ + consys_spi_write_nolock(subsystem, 0x070, 0x00000005); + + /* BG thermal sensor offset update */ + consys_spi_write_nolock(subsystem, 0x344, 0x00000088); + + /* BG thermal sensor offset update */ + consys_spi_write_nolock(subsystem, 0x374, 0x00000088); + + /* BG thermal sensor offset update */ + consys_spi_write_nolock(subsystem, 0x3A4, 0x00000088); + + /* BG thermal sensor offset update */ + consys_spi_write_nolock(subsystem, 0x3D4, 0x00000088); + + /* set WCON VDD IPTAT to "0000" */ + consys_spi_write_nolock(subsystem, 0xA80, 0x44D07000); + + /* change back LTBUF SX3 drving to default value, 20191113 */ + consys_spi_write_nolock(subsystem, 0xA88, 0x3900AAAA); + + /* SM input cap off */ + consys_spi_write_nolock(subsystem, 0x2C4, 0x00000000); + + + return 0; +} + +int _connsys_a_die_cfg_7975(unsigned char adie_idx) +{ + int check; + unsigned int adie_chip_id = 0x0; + unsigned char subsystem = 0; + + if (adie_idx == 1) + subsystem = SYS_SPI_2ND_ADIE_TOP; + else + subsystem = SYS_SPI_TOP; + + /* release D Die to A Die Digital reset_b */ + if (adie_idx == 1) + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x4); + else + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x1); + + /* Get semaphore once */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("Require semaphore fail\n"); + return -1; + } + + /* read a-die ID */ + check = consys_spi_read_nolock(subsystem, ATOP_CHIP_ID, &adie_chip_id); + if (check) { + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + pr_err("Get ATOP_CHIP_ID fail, check=%d\n", check); + return -1; + } + + if (adie_idx < AIDE_NUM_MAX) { + conn_hw_env[adie_idx].valid = true; + conn_hw_env[adie_idx].adie_hw_version = (adie_chip_id & 0xFFFF); + conn_hw_env[adie_idx].adie_id = ((adie_chip_id & 0xFFFF0000) >> 16); + conn_hw_env[adie_idx].is_rc_mode = 0; + + pr_info("adie_idx[%d], A-die CHIP ID = 0x%x, HW Version = 0x%x\n", + adie_idx, conn_hw_env[adie_idx].adie_id, conn_hw_env[adie_idx].adie_hw_version); + } + + /* enable TOPDIG CK */ + check = consys_spi_write_nolock(subsystem, ATOP_TOP_CLK_EN, 0xFFFFFFFF); + + /* Thermal Cal (TOP) */ + _connsys_a_die_thermal_cal(subsystem); + + /* XTAL TRIM */ + _connsys_a_die_xtal_trim_7975(subsystem); + + /* Form Harrier E2 Patch */ + _connsys_a_die_form_patch_7975(subsystem); + + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return 0; +} + +int connsys_a_die_cfg(void) +{ + int ret; + memset(&conn_hw_env, 0, sizeof(conn_hw_env)); + + if (adie_7976){ + if (adie_cfg_type == ADIE_TYPE_TWO) { + ret = _connsys_a_die_cfg_7976(0); + ret = _connsys_a_die_cfg_7976(1); + } else { + if (one_adie_dbdc) { + ret = _connsys_a_die_cfg_7976(0); + } else { + ret = _connsys_a_die_cfg_7976(1); + } + } + } else { + if (adie_cfg_type == ADIE_TYPE_TWO) { + ret = _connsys_a_die_cfg_7975(0); + ret = _connsys_a_die_cfg_7975(1); + } else { + if (!one_adie_dbdc) + ret = _connsys_a_die_cfg_7975(1); + } + } + + return ret; +} + +int _connsys_afe_wbg_cal_7976(unsigned char wbg_idx, unsigned char rfspi_idx) +{ + int check; + unsigned long afe_ctl_addr = 0; + unsigned char subsystem = 0; + + if ((wbg_idx == 0) && (rfspi_idx == 0)) { + afe_ctl_addr = REG_CONN_AFE_CTL_ADDR; + subsystem = SYS_SPI_TOP; + } else if ((wbg_idx == 1) && (rfspi_idx == 0)) { + afe_ctl_addr = REG_CONN_AFE_CTL_2ND_ADDR; + subsystem = SYS_SPI_TOP; + } else if ((wbg_idx == 1) && (rfspi_idx == 1)) { + afe_ctl_addr = REG_CONN_AFE_CTL_2ND_ADDR; + subsystem = SYS_SPI_2ND_ADIE_TOP; + } else { + pr_err("Not support for this combination (wbg_idx=%d, rfspi_idx=%d)\n", + wbg_idx, rfspi_idx); + return -1; + } + + /* Get semaphore once */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("Require semaphore fail\n"); + return -1; + } + + /* set WF_PAD to HighZ */ + check = consys_spi_write_nolock(subsystem, ATOP_RG_ENCAL_WBTAC_IF_SW, 0x88888005); + + /* AFE WBG CAL SEQ1 (RC calibration) */ + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x1); + udelay(60); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x1); + + /* AFE WBG CAL SEQ2 (TX calibration) */ + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_03, (0x1 << 21)); + udelay(30); + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_03, (0x1 << 20)); + udelay(60); + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x203E0000); + udelay(800); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x203E0000); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_03, 0x300000); + + /* disable WF_PAD to HighZ */ + check = consys_spi_write_nolock(subsystem, ATOP_RG_ENCAL_WBTAC_IF_SW, 0x00000005); + + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return 0; +} + +int _connsys_afe_wbg_cal_7975(unsigned char wbg_idx, unsigned char rfspi_idx) +{ + int check; + unsigned long afe_ctl_addr = 0; + unsigned char subsystem = 0; + + if ((wbg_idx == 0) && (rfspi_idx == 0)) { + afe_ctl_addr = REG_CONN_AFE_CTL_ADDR; + subsystem = SYS_SPI_TOP; + } else if ((wbg_idx == 1) && (rfspi_idx == 0)) { + afe_ctl_addr = REG_CONN_AFE_CTL_2ND_ADDR; + subsystem = SYS_SPI_TOP; + } else if ((wbg_idx == 1) && (rfspi_idx == 1)) { + afe_ctl_addr = REG_CONN_AFE_CTL_2ND_ADDR; + subsystem = SYS_SPI_2ND_ADIE_TOP; + } else { + pr_err("Not support for this combination (wbg_idx=%d, rfspi_idx=%d)\n", + wbg_idx, rfspi_idx); + return -1; + } + + /* Get semaphore once */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("Require semaphore fail\n"); + return -1; + } + + /* set WF_PAD to HighZ */ + check = consys_spi_write_nolock(subsystem, ATOP_RG_ENCAL_WBTAC_IF_SW, 0x80000000); + + /* AFE WBG CAL SEQ1 (RC calibration) */ + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x1); + udelay(60); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x1); + + /* AFE WBG CAL SEQ2 (TX calibration) */ + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_03, (0x1 << 21)); + udelay(30); + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_03, (0x1 << 20)); + udelay(60); + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x3E0000); + udelay(800); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x3E0000); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_03, 0x300000); + + /* disable WF_PAD to HighZ */ + check = consys_spi_write_nolock(subsystem, ATOP_RG_ENCAL_WBTAC_IF_SW, 0x00000005); + + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return 0; +} + +int connsys_afe_wbg_cal(void) +{ + int ret; + + if (adie_7976){ + if (adie_cfg_type == ADIE_TYPE_TWO) { + ret = _connsys_afe_wbg_cal_7976(0, 0); + ret = _connsys_afe_wbg_cal_7976(1, 1); + } else { + if (one_adie_dbdc) { + ret = _connsys_afe_wbg_cal_7976(0, 0); + } else { + ret = _connsys_afe_wbg_cal_7976(1, 1); + } + } + } else { + if (adie_cfg_type == ADIE_TYPE_TWO) { + ret = _connsys_afe_wbg_cal_7975(0, 0); + ret = _connsys_afe_wbg_cal_7975(1, 1); + } else { + if (!one_adie_dbdc) + ret = _connsys_afe_wbg_cal_7975(1, 1); + } + } + + return ret; +} + +int _connsys_subsys_pll_initial(unsigned char wbg_idx) +{ + unsigned long afe_ctl_addr = 0; + + if (wbg_idx == 0) { + afe_ctl_addr = REG_CONN_AFE_CTL_ADDR; + } else if (wbg_idx == 1) { + afe_ctl_addr = REG_CONN_AFE_CTL_2ND_ADDR; + } else { + pr_err("Not support for this wbg index (wbg_idx=%d)\n", wbg_idx); + return -1; + } + + /* SWITCH(xtal_freq) + CASE SYS_XTAL_40000K + */ + /* set BPLL stable time = 30us (value = 30 * 1000 *1.01 / 25ns) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_PLL_STB_TIME, (0x4BC << 16), 30, 16); + /* set WPLL stable time = 50us (value = 50 * 1000 *1.01 / 25ns) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_PLL_STB_TIME, 0x7E4, 14, 0); + /* BT pll_en will turn on BPLL only (may change in different XTAL option) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_DIG_EN_02, (0x1 << 6), 7, 6); + /* WF pll_en will turn on WPLL only (may change in different XTAL option) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_DIG_EN_02, 0x2, 1, 0); + /* MCU pll_en will turn on BPLL (may change in different XTAL option) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_DIG_EN_02, (0x1 << 2), 3, 2); + /* MCU pll_en will turn on BPLL + WPLL (may change in different XTAL option) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_DIG_EN_02, (0x2 << 16), 17, 16); + /* CONN_INFRA CLKGEN WPLL AND BPLL REQUEST */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_DIG_TOP_01, (0x9 << 15), 18, 15); + + return 0; +} + +int connsys_subsys_pll_initial(void) +{ + int ret; + + ret = _connsys_subsys_pll_initial(0); + + return ret; +} + +int connsys_osc_legacy_mode(void) +{ + /* disable conn_top rc osc_ctrl_top */ + CONSYS_CLR_BIT(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_CFG_RC_CTL_0, 0x80); + CONSYS_REG_WRITE_RANGE(REG_CONN_INFRA_CFG_ADDR + OSC_CTL_0, 0x80706, 23, 0); + + return 0; +} + +int connsys_top_pwr_ctrl(void) +{ + /* prevent subsys from power on/of in a short time interval */ + CONSYS_CLR_BIT_WITH_KEY(REG_CONN_INFRA_RGU_ADDR + BGFYS_ON_TOP_PWR_CTL, 0x40, 0x42540000); + CONSYS_CLR_BIT_WITH_KEY(REG_CONN_INFRA_RGU_ADDR + WFSYS_ON_TOP_PWR_CTL, 0x40, 0x57460000); + + return 0; +} + +int connsys_conn_infra_bus_timeout(void) +{ + /* set conn_infra_off bus timeout */ + CONSYS_REG_WRITE_RANGE(REG_CONN_INFRA_BUS_CR_ADDR + CONN_INFRA_BUS_OFF_TIMEOUT_CTRL, (0x2 << 7), 14, 7); + /* enable conn_infra off bus timeout feature */ + CONSYS_REG_WRITE_RANGE(REG_CONN_INFRA_BUS_CR_ADDR + CONN_INFRA_BUS_OFF_TIMEOUT_CTRL, 0xF, 3, 0); + + /* set conn_infra_on bus timeout */ + CONSYS_REG_WRITE_RANGE(REG_CONN_INFRA_BUS_CR_ADDR + CONN_INFRA_BUS_ON_TIMEOUT_CTRL, (0xC << 7), 14, 7); + /* enable conn_infra_on bus timeout feature */ + CONSYS_REG_WRITE_RANGE(REG_CONN_INFRA_BUS_CR_ADDR + CONN_INFRA_BUS_ON_TIMEOUT_CTRL, 0xF, 3, 0); + + return 0; +} + +int connsys_clkgen_wpll_hw_ctrl(void) +{ + /* set hclk_div_1 with wpll div sel */ + CONSYS_REG_WRITE_MASK(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS_WPLL_DIV_1, 0x4, 0xFC); + + /* set hclk_div_2 with wpll div sel */ + CONSYS_REG_WRITE_MASK(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS_WPLL_DIV_2, 0x4, 0xFC); + +#ifndef CONFIG_FPGA_EARLY_PORTING + /* enable conn_infra bus wpll div_1 */ + CONSYS_SET_BIT(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS_WPLL_DIV_1, 0x1); + + /* enable conn_infra bus wpll div_2 */ + CONSYS_SET_BIT(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS_WPLL_DIV_2, 0x1); +#endif + +#ifndef CONFIG_FPGA_EARLY_PORTING + /* set rfspi wpll div sel + enable rfspis wpll div + */ + CONSYS_REG_WRITE_MASK(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_RFSPI_WPLL_DIV, 0x21, 0xFD); +#else + /* set rfspi wpll div sel */ + CONSYS_REG_WRITE_MASK(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_RFSPI_WPLL_DIV, 0x20, 0xFC); +#endif + + /* disable conn_infra bus clock sw control ==> conn_infra bus clock hw control */ + CONSYS_CLR_BIT(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS, 0x800000); + + /* Conn_infra HW_CONTROL => conn_infra enter dsleep mode */ + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_CFG_PWRCTRL0, 0x1); + + return 0; +} + +int consys_conninfra_top_wakeup(void) +{ + /* wake up conn_infra */ + CONSYS_SET_BIT(REG_CONN_HOST_CSR_TOP_ADDR + CONN_INFRA_WAKEPU_TOP, 0x1); + + /* Wait 900us (apply this for CONNSYS XO clock ready) */ + udelay(900); + + /* Check CONNSYS version ID + * (polling "10 times" for specific project code and each polling interval is "1ms") + */ + if (consys_polling_chipid() != 0) { + pr_err("Polling chip id fail\n"); + return -1; + } + + return 0; +} + +int consys_conninfra_top_sleep(void) +{ + /* release conn_infra force on */ + CONSYS_CLR_BIT(REG_CONN_HOST_CSR_TOP_ADDR + CONN_INFRA_WAKEPU_TOP, 0x1); + + return 0; +} + +int _consys_adie_top_ck_en_on_off_ctrl(unsigned char rfspi_idx, enum consys_drv_type type, unsigned char on) +{ + int check = 0; + unsigned long slp_ctl_addr = 0; + + if (rfspi_idx == 1) + slp_ctl_addr = REG_INST2_CONN_WT_SLP_CTL_REG_ADDR; + else + slp_ctl_addr = REG_CONN_WT_SLP_CTL_REG_ADDR; + + if (type == CONNDRV_TYPE_CONNINFRA) { + if (on) + CONSYS_SET_BIT(slp_ctl_addr + WB_SLP_TOP_CK_0, 0x1); + else + CONSYS_CLR_BIT(slp_ctl_addr + WB_SLP_TOP_CK_0, 0x1); + CONSYS_REG_BIT_POLLING(slp_ctl_addr + WB_SLP_TOP_CK_0, 1, 0, 100, 500, check); + if (check == -1) + pr_err("[type=%d][on=%d] op= fail\n", type, on); + } else if (type == CONNDRV_TYPE_WIFI) { + if (on) + CONSYS_SET_BIT(slp_ctl_addr + WB_SLP_TOP_CK_1, 0x1); + else + CONSYS_CLR_BIT(slp_ctl_addr + WB_SLP_TOP_CK_1, 0x1); + CONSYS_REG_BIT_POLLING(slp_ctl_addr + WB_SLP_TOP_CK_1, 1, 0, 100, 500, check); + if (check == -1) + pr_err("[type=%d][on=%d] op= fail\n", type, on); + } else { + pr_err("Not support for this consys drv type = %d\n", type); + return -1; + } + + return 0; +} + +int consys_adie_top_ck_en_on_off_ctrl(enum consys_drv_type type, unsigned char on) +{ + int ret; + + if (consys_sema_acquire_timeout(CONN_SEMA_CONN_INFRA_COMMON_SYSRAM_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("[type=%d] acquire semaphore (%d) timeout\n", + type, CONN_SEMA_CONN_INFRA_COMMON_SYSRAM_INDEX); + return -1; + } + + if (adie_cfg_type == ADIE_TYPE_TWO) { + ret = _consys_adie_top_ck_en_on_off_ctrl(0, type, on); + ret = _consys_adie_top_ck_en_on_off_ctrl(1, type, on); + } else { + if (one_adie_dbdc) { + ret = _consys_adie_top_ck_en_on_off_ctrl(0, type, on); + } else { + ret = _consys_adie_top_ck_en_on_off_ctrl(1, type, on); + } + } + + consys_sema_release(CONN_SEMA_CONN_INFRA_COMMON_SYSRAM_INDEX); + + return ret; +} + +int consys_conninfra_wf_wakeup(void) +{ + /* wake up conn_infra */ + CONSYS_SET_BIT(REG_CONN_HOST_CSR_TOP_ADDR + CONN_INFRA_WAKEPU_WF, 0x1); + + /* Wait 900us (apply this for CONNSYS XO clock ready) */ + udelay(900); + + /* Check CONNSYS version ID + * (polling "10 times" for specific project code and each polling interval is "1ms") + */ + if (consys_polling_chipid() != 0) { + pr_err("Polling chip id fail\n"); + return -1; + } + + return 0; +} + +int consys_conninfra_wf_sleep(void) +{ + CONSYS_CLR_BIT(REG_CONN_HOST_CSR_TOP_ADDR + CONN_INFRA_WAKEPU_WF, 0x1); + + return 0; +} + +int consys_conn_wmcpu_sw_reset(bool bassert) +{ + if (bassert) + CONSYS_CLR_BIT(REG_CONN_INFRA_RGU_ADDR + WFSYS_CPU_SW_RST_B, 0x1); + else + CONSYS_SET_BIT(REG_CONN_INFRA_RGU_ADDR + WFSYS_CPU_SW_RST_B, 0x1); + + return 0; +} + +int consys_wf_bus_slp_prot_ctrl(bool enable) +{ + /* Turn on/off "conn_infra to wfsys"/wfsys to conn_infra/wfdma2conn" bus sleep protect */ + + if (enable) + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_CTRL, 0x1); + else + CONSYS_CLR_BIT(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_CTRL, 0x1); + + return 0; +} + +int consys_wfsys_top_on_ctrl(bool enable) +{ + int check = 0; + + if (enable) { + /* turn on wfsys_top_on */ + CONSYS_SET_BIT(REG_CONN_INFRA_RGU_ADDR + WFSYS_ON_TOP_PWR_CTL, 0x57460080); + + /* polling wfsys_rgu_off_hreset_rst_b */ + CONSYS_REG_BIT_POLLING(REG_CONN_HOST_CSR_TOP_ADDR + DBG_DUMMY_3, 30, 1, 100, 500, check); + if (check == -1) + pr_err("[%d] polling wfsys_rgu_off_hreset_rst_b fail\n", enable); + } else { + /* turn off wfsys_top_on */ + CONSYS_CLR_BIT_WITH_KEY(REG_CONN_INFRA_RGU_ADDR + WFSYS_ON_TOP_PWR_CTL, 0x80, 0x57460000); + + /* polling wfsys_rgu_off_hreset_rst_b */ + CONSYS_REG_BIT_POLLING(REG_CONN_HOST_CSR_TOP_ADDR + DBG_DUMMY_3, 30, 0, 100, 500, check); + if (check == -1) + pr_err("[%d] polling wfsys_rgu_off_hreset_rst_b fail\n", enable); + } + + return 0; +} + +int consys_wfsys_bus_slp_prot_check(bool enable) +{ + int check = 0; + + if (enable) { + /* check "conn_infra to wfsys"/wfsys to conn_infra" bus sleep protect turn off */ + CONSYS_REG_BIT_POLLING(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_STATUS, 29, 0, 100, 500, check); + if (check == -1) + pr_err("[bit %d] check conn_infra to wfsys or wfsys to conn_infra bus sleep protect turn off fail\n", 29); + + CONSYS_REG_BIT_POLLING(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_STATUS, 31, 0, 100, 500, check); + if (check == -1) + pr_err("[bit %d] check conn_infra to wfsys or wfsys to conn_infra bus sleep protect turn off fail\n", 31); + + /* check WFDMA2CONN AXI TX bus sleep protect turn off */ + CONSYS_REG_BIT_POLLING(REG_WF_TOP_SLPPROT_ON_ADDR + WF_TOP_SLPPROT_ON_STATUS_READ, 23, 0, 100, 500, check); + if (check == -1) + pr_err("check WFDMA2CONN AXI TX bus sleep protect turn off fail\n"); + + /* check WFDMA2CONN AXI RX bus sleep protect turn off */ + CONSYS_REG_BIT_POLLING(REG_WF_TOP_SLPPROT_ON_ADDR + WF_TOP_SLPPROT_ON_STATUS_READ, 21, 0, 100, 500, check); + if (check == -1) + pr_err("check WFDMA2CONN AXI RX bus sleep protect turn off fail\n"); + + /* check WFSYS version ID */ + CONSYS_REG_POLLING_LARGER_OR_EQUAL(REG_WF_TOP_CFG_ADDR + WF_TOP_CFG_IP_VERSION, 0xFFFFFFFF, 0, 0x02060000, 10, 500, check); + if (check == -1) + pr_err("check WFSYS version ID fail\n"); + } else { + /* check WFDMA2CONN AXI RX bus sleep protect turn on */ + CONSYS_REG_BIT_POLLING(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_STATUS, 25, 1, 100, 500, check); + if (check == -1) + pr_err("check WFDMA2CONN AXI RX bus sleep protect turn on fail\n"); + + /* check "conn_infra to wfsys"/wfsys to conn_infra" bus sleep protect turn on */ + CONSYS_REG_BIT_POLLING(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_STATUS, 29, 1, 100, 500, check); + if (check == -1) + pr_err("[bit %d] check conn_infra to wfsys or wfsys to conn_infra bus sleep protect turn on fail\n", 29); + + CONSYS_REG_BIT_POLLING(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_STATUS, 31, 1, 100, 500, check); + if (check == -1) + pr_err("[bit %d] check conn_infra to wfsys or wfsys to conn_infra bus sleep protect turn on fail\n", 31); + } + + return 0; +} + +int consys_wfsys_bus_timeout_ctrl(void) +{ + /* set wfsys bus timeout value (ahb apb timeout) */ + CONSYS_REG_WRITE_MASK(REG_WF_MCU_CONFIG_LS_ADDR + BUSHANGCR, 0x1, 0xFF); + + /* enable wfsys bus timeout (ahb apb timeout) */ + CONSYS_SET_BIT(REG_WF_MCU_CONFIG_LS_ADDR + BUSHANGCR, 0x90000000); + + /* set conn2wf remapping window to wf debug_ctrl_ao CR */ + CONSYS_REG_WRITE(REG_WF_MCU_BUS_CR_ADDR + AP2WF_REMAP_1, 0x810F0000); + + /* set wfsys bus timeout value (debug ctrl ao) */ + CONSYS_REG_WRITE_MASK(REG_WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_ADDR + WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_WFMCU_PWA_CTRL0, + 0x03AA0000, 0xFFFF0000); + + /* enable wfsys bus timeout (debug ctrl ao) */ + CONSYS_SET_BIT(REG_WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_ADDR + WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_WFMCU_PWA_CTRL0, 0xC); + + return 0; +} + +int consys_wmcpu_idle_loop_check(void) +{ + int check = 0; + + /* check CONNSYS power-on completion */ + CONSYS_REG_POLLING_EQUAL(REG_WF_TOP_CFG_ON_ADDR + ROMCODE_INDEX, 0xFFFFFFFF, 0, 0x1D1E, 5000, 1000, check); + if (check == -1) + pr_err("check CONNSYS power-on completion fail\n"); + + return 0; +} + +void _consys_check_sku_cfg(void) +{ + unsigned int hw_sku_type = 0; + + if (one_adie_dbdc) { + if (adie_cfg_type == ADIE_TYPE_ONE) + hw_sku_type = 3000; + } + + if (hw_sku_type) + printk(GRN("SKU Type: %d"), hw_sku_type); + else + printk(GRN("Unknown SKU Type\n")); +} + +int consys_plt_adie_type_cfg(void) +{ + /* + If One_Adie_DB: + then TOP_MISC_CR (0x11D1_021C[31:28]) = 0x7 && 0x18050000 = 0x7 + */ + + if (one_adie_dbdc) { + if (adie_cfg_type == ADIE_TYPE_ONE) { + CONSYS_REG_WRITE_MASK(REG_TOP_MISC_ADDR + TOP_MISC_RSRV_ALL1_3, 0x70000000, 0xF0000000); + CONSYS_REG_WRITE(REG_CONN_INFRA_SYSRAM_ADDR + SYSRAM_BASE_ADDR, 0x7); + } + } + + if (_consys_check_adie_cfg() == 0) + _consys_check_sku_cfg(); + + return 0; +} + +int consys_wpll_ctrl(bool enable) +{ + if (enable) { + /* turn back wpll setting in conn_afe_ctl by setting wpll initial control to 2'b10 */ + CONSYS_REG_WRITE_MASK(REG_CONN_AFE_CTL_ADDR + RG_DIG_EN_02, 0x20002, 0x30003); + } else { + /* Don't need below code check anymore due to new design */ +#if 0 + int check = 0; + /* trun off wpll enable in conn_afe_ctl by setting wpll initial control to 2'b00 */ + CONSYS_REG_WRITE_MASK(REG_CONN_AFE_CTL_ADDR + RG_DIG_EN_02, 0x0, 0x30003); + + /* polling conn_infra bus to non-wpll case */ + CONSYS_REG_POLLING_EQUAL(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS, 0x7800, 11, 0x0, 5000, 1000, check); + if (check == -1) + pr_err("polling conn_infra bus to non-wpll case fail\n"); +#endif + } + return 0; +} + +int consys_conninfra_wf_req_clr(void) +{ + /* clear wf_emi_req */ + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + EMI_CTL_WF, 0x1); + CONSYS_CLR_BIT(REG_CONN_INFRA_CFG_ADDR + EMI_CTL_WF, 0x1); + + /* clear wf_infra_req */ + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + EMI_CTL_WF, 0x20); + CONSYS_CLR_BIT(REG_CONN_INFRA_CFG_ADDR + EMI_CTL_WF, 0x20); + + return 0; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986.h b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986.h new file mode 100644 index 0000000000..a8dc0a2a34 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7986_H_ +#define _PLATFORM_MT7986_H_ + +enum +{ + ADIE_TYPE_NONE = 0, + ADIE_TYPE_ONE, + ADIE_TYPE_TWO, + ADIE_TYPE_NUM_MAX +}; + +enum conn_semaphore_type +{ + CONN_SEMA_CHIP_POWER_ON_INDEX = 0, + CONN_SEMA_CALIBRATION_INDEX = 1, + CONN_SEMA_FW_DL_INDEX = 2, + CONN_SEMA_CLOCK_SWITCH_INDEX = 3, + CONN_SEMA_CCIF_INDEX = 4, + CONN_SEMA_COEX_INDEX = 5, + CONN_SEMA_USB_EP0_INDEX = 6, + CONN_SEMA_USB_SHARED_INFO_INDEX = 7, + CONN_SEMA_USB_SUSPEND_INDEX = 8, + CONN_SEMA_USB_RESUME_INDEX = 9, + CONN_SEMA_PCIE_INDEX = 10, + CONN_SEMA_RFSPI_INDEX = 11, + CONN_SEMA_EFUSE_INDEX = 12, + CONN_SEMA_THERMAL_INDEX = 13, + CONN_SEMA_FLASH_INDEX = 14, + CONN_SEMA_DEBUG_INDEX = 15, + CONN_SEMA_WIFI_LP_INDEX = 16, + CONN_SEMA_PATCH_DL_INDEX = 17, + CONN_SEMA_SHARED_VAR_INDEX = 18, + CONN_SEMA_CONN_INFRA_COMMON_SYSRAM_INDEX = 19, + CONN_SEMA_NUM_MAX = 32 /* can't be omitted */ +}; + +unsigned int consys_soc_chipid_get(void); +unsigned int consys_get_hw_ver(void); + + +#endif /* _PLATFORM_MT7986_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_consys_reg.h b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_consys_reg.h new file mode 100644 index 0000000000..475e6f06d2 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_consys_reg.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7986_CONSYS_REG_H_ +#define _PLATFORM_MT7986_CONSYS_REG_H_ + +#include "consys_reg_base.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +enum consys_base_addr_index { + TOP_MISC_BASE = 0, /* top_misc */ + TOPRGU_BASE = 1, /* TOPRGU */ + GPIO_BASE = 2, /* GPIO */ + IOCFG_TR_BASE = 3, /* IOCFG_TR */ + IOCFG_TL_BASE = 4, /* IOCFG_TL */ + INFRACFG_AO_BASE = 5, /* infracfg_ao_auto_gen_reg */ + CONN_INFRA_CFG_BASE = 6, /* conn_infra_cfg */ + CONN_INFRA_SYSRAM_BASE = 7, /* conn_infra_sysram */ + CONN_INFRA_CLKGEN_ON_TOP_BASE = 8, /* conn_infra_clkgen_on_top */ + CONN_HOST_CSR_TOP_BASE = 9, /* conn_host_csr_top */ + CONN_INFRA_BUS_CR_BASE = 10, /* conn_infra_bus_cr */ + CONN_INFRA_RGU_BASE = 11, /* conn_infra_rgu */ + CONN_WT_SLP_CTL_REG_BASE = 12, /* conn_wt_slp_ctl_reg */ + INST2_CONN_WT_SLP_CTL_REG_BASE = 13, /* Inst2_conn_wt_slp_ctl_reg */ + CONN_RF_SPI_MST_REG_BASE = 14, /* conn_rf_spi_mst_reg */ + INST2_CONN_RF_SPI_MST_REG_BASE = 15, /* Inst2_conn_rf_spi_mst_reg */ + CONN_SEMAPHORE_BASE = 16, /* conn_semaphore */ + CONN_AFE_CTL_BASE = 17, /* conn_afe_ctl */ + CONN_AFE_CTL_2ND_BASE = 18, /* conn_afe_ctl_2nd */ + WF_TOP_SLPPROT_ON_BASE = 19, /* wf_top_slpprot_on by remapping to 0x81020000 */ + WF_TOP_CFG_BASE = 20, /* wf_top_cfg by remapping to 0x80020000 */ + WF_MCU_CONFIG_LS_BASE = 21, /* wf_mcu_confg_ls by remapping to 0x88000000 */ + WF_MCU_BUS_CR_BASE = 22, /* wf_mcu_bus_cr by remapping to 0x830C0XXX */ + WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_BASE = 23, /* wf_mcusys_infra_bus_full_u_debug_ctrl_ao by remapping to 0x810F0000 */ + WF_TOP_CFG_ON_BASE = 24, /* wf_top_cfg_on by remapping to 0x81021000 */ + CONSYS_BASE_ADDR_MAX +}; + +struct consys_base_addr { + struct consys_reg_base_addr reg_base_addr[CONSYS_BASE_ADDR_MAX]; +}; + +extern struct consys_base_addr conn_reg; + +#define REG_TOP_MISC_ADDR conn_reg.reg_base_addr[TOP_MISC_BASE].vir_addr +#define REG_TOP_RGU_ADDR conn_reg.reg_base_addr[TOPRGU_BASE].vir_addr +#define REG_GPIO_BASE_ADDR conn_reg.reg_base_addr[GPIO_BASE].vir_addr +#define REG_IOCFG_TR_ADDR conn_reg.reg_base_addr[IOCFG_TR_BASE].vir_addr +#define REG_IOCFG_TL_ADDR conn_reg.reg_base_addr[IOCFG_TL_BASE].vir_addr +#define REG_INFRACFG_AO_ADDR conn_reg.reg_base_addr[INFRACFG_AO_BASE].vir_addr +#define REG_CONN_INFRA_CFG_ADDR conn_reg.reg_base_addr[CONN_INFRA_CFG_BASE].vir_addr +#define REG_CONN_INFRA_SYSRAM_ADDR conn_reg.reg_base_addr[CONN_INFRA_SYSRAM_BASE].vir_addr +#define REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR conn_reg.reg_base_addr[CONN_INFRA_CLKGEN_ON_TOP_BASE].vir_addr +#define REG_CONN_HOST_CSR_TOP_ADDR conn_reg.reg_base_addr[CONN_HOST_CSR_TOP_BASE].vir_addr +#define REG_CONN_INFRA_BUS_CR_ADDR conn_reg.reg_base_addr[CONN_INFRA_BUS_CR_BASE].vir_addr +#define REG_CONN_INFRA_RGU_ADDR conn_reg.reg_base_addr[CONN_INFRA_RGU_BASE].vir_addr +#define REG_CONN_WT_SLP_CTL_REG_ADDR conn_reg.reg_base_addr[CONN_WT_SLP_CTL_REG_BASE].vir_addr +#define REG_INST2_CONN_WT_SLP_CTL_REG_ADDR conn_reg.reg_base_addr[INST2_CONN_WT_SLP_CTL_REG_BASE].vir_addr +#define REG_CONN_RF_SPI_MST_REG_ADDR conn_reg.reg_base_addr[CONN_RF_SPI_MST_REG_BASE].vir_addr +#define REG_INST2_CONN_RF_SPI_MST_REG_ADDR conn_reg.reg_base_addr[INST2_CONN_RF_SPI_MST_REG_BASE].vir_addr +#define REG_CONN_SEMAPHORE_ADDR conn_reg.reg_base_addr[CONN_SEMAPHORE_BASE].vir_addr +#define REG_CONN_AFE_CTL_ADDR conn_reg.reg_base_addr[CONN_AFE_CTL_BASE].vir_addr +#define REG_CONN_AFE_CTL_2ND_ADDR conn_reg.reg_base_addr[CONN_AFE_CTL_2ND_BASE].vir_addr +#define REG_WF_TOP_SLPPROT_ON_ADDR conn_reg.reg_base_addr[WF_TOP_SLPPROT_ON_BASE].vir_addr +#define REG_WF_TOP_CFG_ADDR conn_reg.reg_base_addr[WF_TOP_CFG_BASE].vir_addr +#define REG_WF_MCU_CONFIG_LS_ADDR conn_reg.reg_base_addr[WF_MCU_CONFIG_LS_BASE].vir_addr +#define REG_WF_MCU_BUS_CR_ADDR conn_reg.reg_base_addr[WF_MCU_BUS_CR_BASE].vir_addr +#define REG_WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_ADDR conn_reg.reg_base_addr[WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_BASE].vir_addr +#define REG_WF_TOP_CFG_ON_ADDR conn_reg.reg_base_addr[WF_TOP_CFG_ON_BASE].vir_addr + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +struct consys_base_addr* get_conn_reg_base_addr(void); + +#endif /* _PLATFORM_MT7986_CONSYS_REG_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_consys_reg_offset.h b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_consys_reg_offset.h new file mode 100644 index 0000000000..19e4a855e3 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_consys_reg_offset.h @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7986_CONSYS_REG_OFFSET_H_ +#define _PLATFORM_MT7986_CONSYS_REG_OFFSET_H_ + +/**********************************************************************/ +/* Base: TOP_MISC (0x11D1_0000) */ +/**********************************************************************/ +#define CONNSYS_MISC 0x0114 +#define TOP_MISC_RSRV_ALL1_3 0x021C + + +/**********************************************************************/ +/* Base: TOP RGU (0x1001_C000) */ +/**********************************************************************/ +#define TOP_RGU_WDT_SWSYSRST 0x0018 + +/**********************************************************************/ +/* Base: GPIO (0x1001_F000) */ +/**********************************************************************/ +#define GPIO_MODE9 0x0390 +#define GPIO_MODE10 0x03A0 +#define GPIO_MODE11 0x03B0 +#define GPIO_MODE12 0x03C0 + +/**********************************************************************/ +/* Base: IOCFG_TR (0x11F0_0000) */ +/**********************************************************************/ +#define IOCFG_TR_DRV_CFG0 0x0000 +#define IOCFG_TR_DRV_CFG1 0x0010 + +/**********************************************************************/ +/* Base: IOCFG_TL (0x11F1_0000) */ +/**********************************************************************/ +#define IOCFG_TL_DRV_CFG0 0x0000 +#define IOCFG_TL_DRV_CFG1 0x0010 + +/**********************************************************************/ +/* Base: INFRACFG_AO (0x1000_3000) */ +/**********************************************************************/ +#define CONN2AP_GALS_SLPPROT 0x00D0 +#define AP2CONN_GALS_SLPPROT 0x00D4 + +/**********************************************************************/ +/* Base: CONN_INFRA_CFG (0x1800_1000) */ +/**********************************************************************/ +#define CONN_INFRA_CFG_IP_VERSION 0x0000 +#define EFUSE 0x0020 +#define ADIE_CTL 0x0030 +#define CONN_INFRA_CFG_PWRCTRL0 0x0200 +#define CONN_INFRA_CFG_RC_CTL_0 0x0380 +#define OSC_CTL_0 0x0300 +#define EMI_CTL_WF 0x0414 +#define CONN_INFRA_WF_SLP_CTRL 0x0540 +#define CONN_INFRA_WF_SLP_STATUS 0x0544 + +/**********************************************************************/ +/* Base: CONN_INFRA_SYSRAM (0x1805_0000) */ +/**********************************************************************/ +#define SYSRAM_BASE_ADDR 0x0000 + +/**********************************************************************/ +/* Base: CONN_INFRA_CLKGEN_ON_TOP (0x1800_9000) */ +/**********************************************************************/ +#define CKGEN_BUS_WPLL_DIV_1 0x0008 +#define CKGEN_BUS_WPLL_DIV_2 0x000C +#define CKGEN_RFSPI_WPLL_DIV 0x0040 +#define CKGEN_BUS 0x0A00 + +/**********************************************************************/ +/* Base: CONN_HOST_CSR_TOP (0x1806_0000) */ +/**********************************************************************/ +#define CONN_INFRA_WAKEPU_TOP 0x01A0 +#define CONN_INFRA_WAKEPU_WF 0x01A4 +#define CONN2AP_REMAP_MCU_EMI 0x01C4 +#define CONN2AP_REMAP_WF_PERI 0x01D4 +#define DBG_DUMMY_3 0x02CC + +/**********************************************************************/ +/* Base: CONN_INFRA_BUS_CR (0x1800_E000) */ +/**********************************************************************/ +#define CONN_INFRA_BUS_OFF_TIMEOUT_CTRL 0x0300 +#define CONN_INFRA_BUS_ON_TIMEOUT_CTRL 0x031C +#define CONN2AP_EMI_PATH_ADDR_START 0x0360 +#define CONN2AP_EMI_PATH_ADDR_END 0x0364 + +/**********************************************************************/ +/* Base: CONN_INFRA_RGU (0x1800_0000) */ +/**********************************************************************/ +#define WFSYS_ON_TOP_PWR_CTL 0x0010 +#define BGFYS_ON_TOP_PWR_CTL 0x0020 +#define SYSRAM_HWCTL_PDN 0x0050 +#define SYSRAM_HWCTL_SLP 0x0054 +#define WFSYS_CPU_SW_RST_B 0x0120 + +/**********************************************************************/ +/* Base: CONN_WT_SLP_CTL_REG (0x1800_5000) */ +/* Base: INST2_CONN_WT_SLP_CTL_REG (0x1808_5000) */ +/**********************************************************************/ +#define WB_WF_CK_ADDR 0x0070 +#define WB_WF_WAKE_ADDR 0x0074 +#define WB_WF_ZPS_ADDR 0x0078 +#define WB_TOP_CK_ADDR 0x0084 +#define WB_WF_B0_CMD_ADDR 0x008C +#define WB_WF_B1_CMD_ADDR 0x0090 +#define WB_SLP_TOP_CK_0 0x0120 +#define WB_SLP_TOP_CK_1 0x0124 + +/**********************************************************************/ +/* Base: CONN_RF_SPI_MST_REG (0x1800_4000) */ +/* Base: INST2_CONN_RF_SPI_MST_REG (0x1808_4000) */ +/**********************************************************************/ +#define SPI_STA 0x0000 +#define SPI_WF_ADDR 0x0010 +#define SPI_WF_WDAT 0x0014 +#define SPI_WF_RDAT 0x0018 +#define SPI_BT_ADDR 0x0020 +#define SPI_BT_WDAT 0x0024 +#define SPI_BT_RDAT 0x0028 +#define SPI_FM_ADDR 0x0030 +#define SPI_FM_WDAT 0x0034 +#define SPI_FM_RDAT 0x0038 +#define SPI_GPS_ADDR 0x0040 +#define SPI_GPS_WDAT 0x0044 +#define SPI_GPS_RDAT 0x0048 +#define SPI_TOP_ADDR 0x0050 +#define SPI_TOP_WDAT 0x0054 +#define SPI_TOP_RDAT 0x0058 + +/**********************************************************************/ +/* Base: CONN_SEMAPHORE_BASE (0x1807_0000) */ +/**********************************************************************/ +#define CONN_SEMA00_M2_OWN_STA 0x2000 +#define CONN_SEMA00_M2_OWN_REL 0x2200 +#define CONN_SEMA_OWN_BY_M0_STA_REP 0x0400 +#define CONN_SEMA_OWN_BY_M1_STA_REP 0x1400 +#define CONN_SEMA_OWN_BY_M2_STA_REP 0x2400 +#define CONN_SEMA_OWN_BY_M3_STA_REP 0x3400 +#define CONN_SEMA_OWN_BY_M4_STA_REP 0x4400 +#define CONN_SEMA_OWN_BY_M5_STA_REP 0x5400 +#define CONN_SEMA_OWN_BY_M6_STA_REP 0x6400 +#define CONN_SEMA_OWN_BY_M7_STA_REP 0x7400 + +/**********************************************************************/ +/* Base: CONN_AFE_CTL_BASE (0x1800_3000) */ +/* Base: CONN_AFE_CTL_2ND_BASE (0x1808_3000) */ +/**********************************************************************/ +#define RG_DIG_EN_01 0x0000 +#define RG_DIG_EN_02 0x0004 +#define RG_DIG_EN_03 0x0008 +#define RG_DIG_TOP_01 0x000C +#define RG_PLL_STB_TIME 0x00F4 + +/**********************************************************************/ +/* Base: WF_TOP_SLPPROT_ON_BASE (0x8102_0000 remap to 0x184C_0000) */ +/**********************************************************************/ +#define WF_TOP_SLPPROT_ON_STATUS_READ 0x300C + +/**********************************************************************/ +/* Base: WF_TOP_CFG_BASE (0x8002_0000 remap to 0x184B_0000) */ +/**********************************************************************/ +#define WF_TOP_CFG_IP_VERSION 0x0010 + +/**********************************************************************/ +/* Base: WF_MCU_CONFIG_LS_BASE (0x8800_0000 remap to 0x184F_0000) */ +/**********************************************************************/ +#define BUSHANGCR 0x0440 + +/**********************************************************************/ +/* Base: WF_MCU_BUS_CR_BASE (0x830C_0XXX remap to 0x1840_0XXX) */ +/**********************************************************************/ +#define AP2WF_REMAP_1 0x0120 + +/**********************************************************************/ +/* Base: WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_BASE (0x810F_0000 remap to 0x1850_0000) */ +/**********************************************************************/ +#define WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_WFMCU_PWA_CTRL0 0x0000 + +/**********************************************************************/ +/* Base: WF_TOP_CFG_ON_BASE (0x8102_1000 remap to 0x184C_0000) */ +/**********************************************************************/ +#define ROMCODE_INDEX 0x1604 + +/**********************************************************************/ +/* A-die CR */ +/**********************************************************************/ +#define ATOP_CHIP_ID 0x02C +#define ATOP_TOP_CLK_EN 0xA00 +#define ATOP_RG_ENCAL_WBTAC_IF_SW 0x070 +#define ATOP_RG_WRI_CK_SELECT 0x4AC +#define ATOP_EFUSE_CTRL_1 0x108 +#define ATOP_EFUSE_CTRL_2 0x148 +#define ATOP_EFUSE_CTRL_3 0x14C +#define ATOP_EFUSE_CTRL_4 0x15C +#define ATOP_EFUSE_RDATA0 0x130 +#define ATOP_EFUSE_RDATA1 0x134 +#define ATOP_EFUSE_RDATA2 0x138 +#define ATOP_EFUSE_RDATA3 0x13C +#define ATOP_RG_EFUSE_CFG5 0x144 +#define ATOP_THADC_ANALOG 0x3A6 +#define ATOP_THADC_SLOP 0x3A7 +#define ATOP_RG_TOP_THADC_BG 0x034 +#define ATOP_RG_TOP_THADC_00 0x038 + +#define ATOP_XTAL_TRIM_FLOW 0x3AC +#define ATOP_XTAL_CR_C1_SEL_AXM_80M_OSC 0x390 +#define ATOP_XTAL_CR_C1_SEL_AXM_40M_OSC 0x391 +#define ATOP_XTAL_CR_C1_SEL_AXM_TRIM1_80M_OSC 0x398 +#define ATOP_XTAL_CR_C1_SEL_AXM_TRIM1_40M_OSC 0x399 +#define ATOP_RG_STRAP_PIN_IN 0x4FC +#define ATOP_RG_XO_01 0x65C +#define ATOP_RG_XO_03 0x664 + + +#define ATOP_7975_XTAL_CALIBRATION 0x3A1 +#define ATOP_7975_XTAL_TRIM2_COMPENSATION 0x3A2 +#define ATOP_7975_XTAL_TRIM3_COMPENSATION 0x3A3 +#define ATOP_7975_XTAL_TRIM4_COMPENSATION 0x3A4 +#define ATOP_7975_XTAL_TRIM_FLOW 0x3A5 +#define ATOP_7975_CR_C1_C2_A94 0xA94 +#define ATOP_7975_CR_C1_C2_A18 0xA18 +#define ATOP_7975_CR_C1_C2_A84 0xA84 +#define ATOP_7975_CR_C1_C2_AA4 0xAA4 +#define ATOP_7975_CO_CLK 0xA1C + + +#endif /* _PLATFORM_MT7986_CONSYS_REG_OFFSET_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_emi.h b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_emi.h new file mode 100644 index 0000000000..663a4a0879 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_emi.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7986_EMI_H_ +#define _PLATFORM_MT7986_EMI_H_ + +#include "osal.h" +#include "emi_mng.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +struct consys_platform_emi_ops* get_consys_platform_emi_ops(void); + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +#endif /* _PLATFORM_MT7986_EMI_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_pmic.h b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_pmic.h new file mode 100644 index 0000000000..165816d835 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_pmic.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7986_PMIC_H_ +#define _PLATFORM_MT7986_PMIC_H_ + +#include "osal.h" +#include "pmic_mng.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +struct consys_platform_pmic_ops* get_consys_platform_pmic_ops(void); + +#endif /* _PLATFORM_MT7986_PMIC_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_pos.h b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_pos.h new file mode 100644 index 0000000000..fc182c5430 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/include/mt7986_pos.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#ifndef _PLATFORM_MT7986_POS_H_ +#define _PLATFORM_MT7986_POS_H_ + +int consys_plt_hw_init(void); +int consys_xtal_ctrl_fast_mode(void); +int consys_sw_reset_ctrl(bool bassert); +int consys_tx_rx_bus_slp_prot_ctrl(bool enable); +void consys_set_if_pinmux(bool enable); +int consys_polling_chipid(void); +int consys_plt_adie_type_check(void); +int consys_plt_adie_type_cfg(void); +int consys_bus_clock_ctrl(enum consys_drv_type drv_type, unsigned int bus_clock); +int consys_emi_set_remapping_reg(void); +int consys_emi_set_region_protection(void); +int connsys_d_die_cfg(void); +int connsys_conninfra_sysram_hw_ctrl(void); +int connsys_spi_master_cfg(void); +int consys_sema_acquire_timeout(unsigned int index, unsigned int usec); +void consys_sema_release(unsigned int index); +int consys_spi_read(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data); +int consys_spi_write(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data); +int consys_spi_write_offset_range(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int value, + unsigned int reg_offset, unsigned int value_offset, unsigned int size); +int connsys_a_die_cfg(void); +int connsys_afe_wbg_cal(void); +int connsys_subsys_pll_initial(void); +int connsys_osc_legacy_mode(void); +int connsys_top_pwr_ctrl(void); +int connsys_conn_infra_bus_timeout(void); +int connsys_clkgen_wpll_hw_ctrl(void); +int consys_conninfra_top_wakeup(void); +int consys_conninfra_top_sleep(void); +int consys_adie_top_ck_en_on_off_ctrl(enum consys_drv_type type, unsigned char on); +int consys_conninfra_wf_wakeup(void); +int consys_conninfra_wf_sleep(void); +int consys_conn_wmcpu_sw_reset(bool bassert); +int consys_wf_bus_slp_prot_ctrl(bool enable); +int consys_wfsys_top_on_ctrl(bool enable); +int consys_wfsys_bus_slp_prot_check(bool enable); +int consys_wfsys_bus_timeout_ctrl(void); +int consys_wmcpu_idle_loop_check(void); +int consys_wpll_ctrl(bool enable); +int consys_conninfra_wf_req_clr(void); + + +#endif /* _PLATFORM_MT7986_POS_H_ */ diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986.c b/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986.c new file mode 100644 index 0000000000..9329eda795 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986.c @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include + +#include "osal.h" +#include "conninfra.h" +#include "consys_hw.h" +#include "consys_reg_mng.h" +#include "consys_reg_util.h" +#include "mt7986.h" +#include "mt7986_pos.h" +#include "emi_mng.h" +#include "mt7986_consys_reg.h" +#include "mt7986_consys_reg_offset.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define PLATFORM_SOC_CHIP 0x7986 +#define CONN_IP_VER 0x02070000 + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +struct consys_hw_ops_struct g_consys_hw_ops_mt7986 = { + /* HW init */ + .consys_plt_hw_init = consys_plt_hw_init, + + /* POS */ + .consys_plt_xtal_ctrl_fast_mode = consys_xtal_ctrl_fast_mode, + .consys_plt_connsys_sw_reset_ctrl = consys_sw_reset_ctrl, + .consys_plt_set_if_pinmux = consys_set_if_pinmux, + .consys_plt_tx_rx_bus_slp_prot_ctrl = consys_tx_rx_bus_slp_prot_ctrl, + .consys_plt_polling_consys_chipid = consys_polling_chipid, + .consys_plt_bus_clock_ctrl = consys_bus_clock_ctrl, + .consys_plt_d_die_cfg = connsys_d_die_cfg, + .consys_plt_conninfra_sysram_hw_ctrl = connsys_conninfra_sysram_hw_ctrl, + .consys_plt_spi_master_cfg = connsys_spi_master_cfg, + .consys_plt_a_die_cfg = connsys_a_die_cfg, + .consys_plt_afe_wbg_cal = connsys_afe_wbg_cal, + .consys_plt_subsys_pll_initial = connsys_subsys_pll_initial, + .consys_plt_osc_legacy_mode = connsys_osc_legacy_mode, + .consys_plt_top_pwr_ctrl = connsys_top_pwr_ctrl, + .consys_plt_conn_infra_bus_timeout = connsys_conn_infra_bus_timeout, + .consys_plt_clkgen_wpll_hw_ctrl = connsys_clkgen_wpll_hw_ctrl, + .consys_plt_conninfra_wakeup = consys_conninfra_top_wakeup, + .consys_plt_conninfra_sleep = consys_conninfra_top_sleep, + .consys_plt_adie_top_ck_en_on_off_ctrl = consys_adie_top_ck_en_on_off_ctrl, + .consys_plt_conninfra_wf_wakeup = consys_conninfra_wf_wakeup, + .consys_plt_conninfra_wf_sleep = consys_conninfra_wf_sleep, + .consys_plt_conn_wmcpu_sw_reset = consys_conn_wmcpu_sw_reset, + .consys_plt_wf_bus_slp_prot_ctrl = consys_wf_bus_slp_prot_ctrl, + .consys_plt_wfsys_top_on_ctrl = consys_wfsys_top_on_ctrl, + .consys_plt_wfsys_bus_slp_prot_check = consys_wfsys_bus_slp_prot_check, + .consys_plt_wfsys_bus_timeout_ctrl = consys_wfsys_bus_timeout_ctrl, + .consys_plt_conn_wmcpu_idle_loop_check = consys_wmcpu_idle_loop_check, + .consys_plt_wpll_ctrl = consys_wpll_ctrl, + .consys_plt_conninfra_wf_req_clr = consys_conninfra_wf_req_clr, + + /* load from dts */ + /* TODO: mtcmos should move to a independent module */ + .consys_plt_clk_get_from_dts = NULL, + .consys_plt_clk_detach = NULL, + + /* clock */ + .consys_plt_soc_chipid_get = consys_soc_chipid_get, + + /* debug */ + .consys_plt_get_hw_ver = consys_get_hw_ver, + .consys_plt_spi_read = consys_spi_read, + .consys_plt_spi_write = consys_spi_write, + .consys_plt_spi_clock_switch = NULL, + .consys_plt_power_state = NULL, + + /* others */ + .consys_plt_adie_type_check = consys_plt_adie_type_check, + .consys_plt_adie_type_cfg = consys_plt_adie_type_cfg, +}; + +/* For mt7986 */ +extern struct consys_hw_ops_struct g_consys_hw_ops_mt7986; +extern struct consys_reg_mng_ops g_dev_consys_reg_ops_mt7986; +extern struct consys_platform_emi_ops g_consys_platform_emi_ops_mt7986; +extern struct consys_platform_pmic_ops g_consys_platform_pmic_ops_mt7986; + +const struct conninfra_plat_data mt7986_plat_data = { + .chip_id = PLATFORM_SOC_CHIP, + .hw_ops = &g_consys_hw_ops_mt7986, + .reg_ops = &g_dev_consys_reg_ops_mt7986, + .platform_emi_ops = &g_consys_platform_emi_ops_mt7986, + .platform_pmic_ops = &g_consys_platform_pmic_ops_mt7986, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ +unsigned int consys_soc_chipid_get(void) +{ + return PLATFORM_SOC_CHIP; +} + +unsigned int consys_get_hw_ver(void) +{ + return CONN_IP_VER; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_consys_reg.c b/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_consys_reg.c new file mode 100644 index 0000000000..290cc9acef --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_consys_reg.c @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include +#include +#include +#include +#include +#include +#include "consys_reg_mng.h" +#include "mt7986_consys_reg.h" +#include "mt7986_consys_reg_offset.h" +#include "consys_hw.h" +#include "consys_reg_util.h" + +#define CFG_REG_LOAD_FROM_DTS_CTRL 0 + +static int consys_reg_init(struct platform_device *pdev); +static int consys_reg_deinit(void); + +struct consys_base_addr conn_reg = { + .reg_base_addr[TOP_MISC_BASE] = {0x11D10000, 0x1000, 0}, + .reg_base_addr[TOPRGU_BASE] = {0x1001C000, 0x1000, 0}, + .reg_base_addr[GPIO_BASE] = {0x1001F000, 0x1000, 0}, + .reg_base_addr[IOCFG_TR_BASE] = {0x11F00000, 0x1000, 0}, + .reg_base_addr[IOCFG_TL_BASE] = {0x11F10000, 0x1000, 0}, + .reg_base_addr[INFRACFG_AO_BASE] = {0x10003000, 0x1000, 0}, + .reg_base_addr[CONN_INFRA_CFG_BASE] = {0x18001000, 0x1000, 0}, + .reg_base_addr[CONN_INFRA_SYSRAM_BASE] = {0x18050000, 0x1000, 0}, + .reg_base_addr[CONN_INFRA_CLKGEN_ON_TOP_BASE] = {0x18009000, 0x1000, 0}, + .reg_base_addr[CONN_HOST_CSR_TOP_BASE] = {0x18060000, 0x1000, 0}, + .reg_base_addr[CONN_INFRA_BUS_CR_BASE] = {0x1800E000, 0x1000, 0}, + .reg_base_addr[CONN_INFRA_RGU_BASE] = {0x18000000, 0x1000, 0}, + .reg_base_addr[CONN_WT_SLP_CTL_REG_BASE] = {0x18005000, 0x1000, 0}, + .reg_base_addr[INST2_CONN_WT_SLP_CTL_REG_BASE] = {0x18085000, 0x1000, 0}, + .reg_base_addr[CONN_RF_SPI_MST_REG_BASE] = {0x18004000, 0x1000, 0}, + .reg_base_addr[INST2_CONN_RF_SPI_MST_REG_BASE] = {0x18084000, 0x1000, 0}, + .reg_base_addr[CONN_SEMAPHORE_BASE] = {0x18070000, 0x10000, 0}, + .reg_base_addr[CONN_AFE_CTL_BASE] = {0x18003000, 0x1000, 0}, + .reg_base_addr[CONN_AFE_CTL_2ND_BASE] = {0x18083000, 0x1000, 0}, + .reg_base_addr[WF_TOP_SLPPROT_ON_BASE] = {0x184C0000, 0x10000, 0}, + .reg_base_addr[WF_TOP_CFG_BASE] = {0x184B0000, 0x1000, 0}, + .reg_base_addr[WF_MCU_CONFIG_LS_BASE] = {0x184F0000, 0x1000, 0}, + .reg_base_addr[WF_MCU_BUS_CR_BASE] = {0x18400000, 0x1000, 0}, + .reg_base_addr[WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_BASE] = {0x18500000, 0x1000, 0}, + .reg_base_addr[WF_TOP_CFG_ON_BASE] = {0x184C0000, 0x10000, 0}, +}; + +const char* consys_base_addr_index_to_str[CONSYS_BASE_ADDR_MAX] = { + "TOP_MISC_BASE", + "TOPRGU_BASE", + "GPIO_BASE", + "IOCFG_TR_BASE", + "IOCFG_TL_BASE", + "INFRACFG_AO_BASE", + "CONN_INFRA_CFG_BASE", + "CONN_INFRA_SYSRAM_BASE", + "CONN_INFRA_CLKGEN_ON_TOP_BASE", + "CONN_HOST_CSR_TOP_BASE", + "CONN_INFRA_BUS_CR_BASE", + "CONN_INFRA_RGU_BASE", + "CONN_WT_SLP_CTL_REG_BASE", + "INST2_CONN_WT_SLP_CTL_REG_BASE", + "CONN_RF_SPI_MST_REG_BASE", + "INST2_CONN_RF_SPI_MST_REG_BASE", + "CONN_SEMAPHORE_BASE", + "CONN_AFE_CTL_BASE", + "CONN_AFE_CTL_2ND_BASE", + "WF_TOP_SLPPROT_ON_BASE", + "WF_TOP_CFG_BASE", + "WF_MCU_CONFIG_LS_BASE", + "WF_MCU_BUS_CR_BASE", + "WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_BASE", + "WF_TOP_CFG_ON_BASE" +}; + +struct consys_reg_mng_ops g_dev_consys_reg_ops_mt7986 = { + .consys_reg_mng_init = consys_reg_init, + .consys_reg_mng_deinit = consys_reg_deinit, + .consys_reg_mng_check_reable = NULL, + .consys_reg_mng_is_consys_reg = NULL, + .consys_reg_mng_is_bus_hang = NULL, + .consys_reg_mng_dump_bus_status = NULL, + .consys_reg_mng_dump_conninfra_status = NULL, + .consys_reg_mng_dump_cpupcr = NULL, + .consys_reg_mng_is_host_csr = NULL, +}; + +struct consys_base_addr* get_conn_reg_base_addr() +{ + return &conn_reg; +} + +static int consys_reg_init(struct platform_device *pdev) +{ + int ret = -1; + struct device_node *node = NULL; + struct consys_reg_base_addr *base_addr = NULL; + int i = 0; + + node = pdev->dev.of_node; + if (node) { +#if (CFG_REG_LOAD_FROM_DTS_CTRL == 1) + struct resource res; + int flag; + + for (i = 0; i < CONSYS_BASE_ADDR_MAX; i++) { + base_addr = &conn_reg.reg_base_addr[i]; + ret = of_address_to_resource(node, i, &res); + if (ret) { + pr_err("Get Reg Index(%d-%s) failed\n", i, consys_base_addr_index_to_str[i]); + continue; + } + base_addr->phy_addr = res.start; + base_addr->vir_addr = (unsigned long)of_iomap(node, i); + of_get_address(node, i, &(base_addr->size), &flag); +#if 0 + pr_info("Get Index(%d-%s) phy_addr(0x%zx) vir_addr=(0x%zx) size=(0x%zx)\n", + i, consys_base_addr_index_to_str[i], base_addr->phy_addr, + base_addr->vir_addr, base_addr->size); +#endif + } +#else + for (i = 0; i < CONSYS_BASE_ADDR_MAX; i++) { + base_addr = &conn_reg.reg_base_addr[i]; + if (base_addr->vir_addr == 0) + base_addr->vir_addr = (unsigned long)ioremap(base_addr->phy_addr, base_addr->size); + + pr_info("Get Index(%d-%s) phy_addr(0x%zx) vir_addr=(0x%zx) size=(0x%zx)\n", + i, consys_base_addr_index_to_str[i], base_addr->phy_addr, + base_addr->vir_addr, base_addr->size); + } +#endif + } else { + pr_err("[%s] can't find CONSYS compatible node\n", __func__); + return ret; + } + + return 0; +} + +static int consys_reg_deinit(void) +{ + int i = 0; + + for (i = 0; i < CONSYS_BASE_ADDR_MAX; i++) { + if (conn_reg.reg_base_addr[i].vir_addr) { + pr_info("[%d] Unmap %s (0x%zx)\n", i, consys_base_addr_index_to_str[i], + conn_reg.reg_base_addr[i].vir_addr); + iounmap((void __iomem*)conn_reg.reg_base_addr[i].vir_addr); + conn_reg.reg_base_addr[i].vir_addr = 0; + } + } + + return 0; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_emi.c b/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_emi.c new file mode 100644 index 0000000000..754174ec72 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_emi.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include +#include +#include +#include "mt7986_emi.h" +#include "mt7986.h" +#include "mt7986_consys_reg.h" +#include "consys_hw.h" +#include "consys_reg_util.h" +#include "mt7986_pos.h" + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ +unsigned int consys_emi_get_fw_emi_size(void) +{ + return 0x100000; +} + +struct consys_platform_emi_ops g_consys_platform_emi_ops_mt7986 = { + .consys_ic_emi_set_region_protection = consys_emi_set_region_protection, + .consys_ic_emi_set_remapping_reg = consys_emi_set_remapping_reg, + .consys_ic_emi_get_fw_emi_size = consys_emi_get_fw_emi_size, +}; + +struct consys_platform_emi_ops* get_consys_platform_emi_ops(void) +{ + return &g_consys_platform_emi_ops_mt7986; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_pmic.c b/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_pmic.c new file mode 100644 index 0000000000..d2576b67a1 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_pmic.c @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include + +#include "consys_hw.h" +#include "consys_reg_util.h" +#include "osal.h" +#include "mt7986_pmic.h" +#include "mt7986_pos.h" +#include "mt7986_consys_reg.h" +#include "mt7986_consys_reg_offset.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +struct consys_platform_pmic_ops g_consys_platform_pmic_ops_mt7986 = { + .consys_pmic_get_from_dts = NULL, + .consys_pmic_common_power_ctrl = NULL, + .consys_pmic_wifi_power_ctrl = NULL, + .consys_pmic_bt_power_ctrl = NULL, + .consys_pmic_gps_power_ctrl = NULL, + .consys_pmic_fm_power_ctrl = NULL, + .consys_pmic_event_notifier = NULL, +}; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +struct consys_platform_pmic_ops* get_consys_platform_pmic_ops(void) +{ + return &g_consys_platform_pmic_ops_mt7986; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_pos.c b/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_pos.c new file mode 100644 index 0000000000..c439395ab0 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/mt7986/mt7986_pos.c @@ -0,0 +1,2043 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019 MediaTek Inc. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include +#include "plat_def.h" +#include "consys_reg_util.h" +#include "consys_reg_mng.h" +#include "mt7986_consys_reg.h" +#include "mt7986_consys_reg_offset.h" +#include "mt7986_pos.h" +#include "mt7986.h" +#include "mt7986_emi.h" + + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ +#define MTD_WIFI_NM "Factory" +#define EEPROM_CHIPID_OFFSET 0x0 + +#define EEPROM_BAND0_STREAM_OFFSET 0x190 +#define EEPROM_BAND0_STREAM_TX_MASK 0x7 +#define EEPROM_BAND0_STREAM_TX_BIT_OFFSET 0 +#define EEPROM_BAND0_STREAM_RX_MASK 0x7 +#define EEPROM_BAND0_STREAM_RX_BIT_OFFSET 3 +#define EEPROM_LNA_PA_SELECT_OFFSET 0x197 +#define EEPROM_LNA_PA_SELECT_BAND0_MASK 0x3 +#define EEPROM_LNA_PA_SELECT_BAND0_BIT_OFFSET 2 +#define EEPROM_LNA_PA_SELECT_BAND1_MASK 0x3 +#define EEPROM_LNA_PA_SELECT_BAND1_BIT_OFFSET 4 + + +#define _TO_STR(_x) #_x +#define TO_STR(_x) _TO_STR(_x) +#define RED(_text) "\033[1;31m"_text"\033[0m" +#define GRN(_text) "\033[1;32m"_text"\033[0m" + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ +bool EEPROM_content_valid = false; +bool one_adie_dbdc = false; +unsigned int adie_cfg_type = ADIE_TYPE_NONE; +unsigned int tx_stream = 0; +unsigned int rx_stream = 0; +unsigned int band0_pa_type = 0; +unsigned int band1_pa_type = 0; + +enum LNA_PA_TYPE { + iPAiLNA = 0x0, /* 2b'00 */ + iPAeLNA = 0x1, /* 2b'01 */ + ePAiLNA = 0x2, /* 2b'10 */ + ePAeLNA = 0x3 /* 2b'11 */ +}; + + +struct spi_op { + unsigned int busy_cr; + unsigned int polling_bit; + unsigned int addr_cr; + unsigned int read_addr_format; + unsigned int write_addr_format; + unsigned int write_data_cr; + unsigned int read_data_cr; + unsigned int read_data_mask; +}; + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ +const static char* g_spi_system_name[SYS_SPI_MAX] = { + "SYS_SPI_WF1", + "SYS_SPI_WF", + "SYS_SPI_BT", + "SYS_SPI_FM", + "SYS_SPI_GPS", + "SYS_SPI_TOP", + "SYS_SPI_WF2", + "SYS_SPI_WF3", +}; + +static const struct spi_op spi_op_array[SYS_SPI_MAX] = { + /* SYS_SPI_WF1 */ + { + SPI_STA, 1, SPI_WF_ADDR, 0x00001000, 0x00000000, + SPI_WF_WDAT, SPI_WF_RDAT, 0xFFFFFFFF + }, + /* SYS_SPI_WF */ + { + SPI_STA, 1, SPI_WF_ADDR, 0x00003000, 0x00002000, + SPI_WF_WDAT, SPI_WF_RDAT, 0xFFFFFFFF + }, + /* SYS_SPI_BT */ + { + SPI_STA, 2, SPI_BT_ADDR, 0x00005000, 0x00004000, + SPI_BT_WDAT, SPI_BT_RDAT, 0xFFFFFFFF + }, + /* SYS_SPI_FM */ + { + SPI_STA, 3, SPI_FM_ADDR, 0x00007000, 0x00006000, + SPI_FM_WDAT, SPI_FM_RDAT, 0x0000FFFF + }, + /* SYS_SPI_GPS */ + { + SPI_STA, 4, SPI_GPS_ADDR, 0x00009000, 0x00008000, + SPI_GPS_WDAT, SPI_GPS_RDAT, 0x0000FFFF + }, + /* SYS_SPI_TOP */ + { + SPI_STA, 5, SPI_TOP_ADDR, 0x0000B000, 0x0000A000, + SPI_TOP_WDAT, SPI_TOP_RDAT, 0xFFFFFFFF + }, + /* SYS_SPI_WF2 */ + { + SPI_STA, 1, SPI_WF_ADDR, 0x0000D000, 0x0000C000, + SPI_WF_WDAT, SPI_WF_RDAT, 0xFFFFFFFF + }, + /* SYS_SPI_WF3 */ + { + SPI_STA, 1, SPI_WF_ADDR, 0x0000F000, 0x0000E000, + SPI_WF_WDAT, SPI_WF_RDAT, 0xFFFFFFFF + }, +}; + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +bool _is_flash_content_valid(void) +{ + unsigned short eeFlashId = 0; + + FlashRead(MTD_WIFI_NM, (unsigned char*)&eeFlashId, EEPROM_CHIPID_OFFSET, sizeof(eeFlashId)); + if (eeFlashId == consys_soc_chipid_get()) { + EEPROM_content_valid = true; + printk(GRN("eeFlashId: 0x%x, EEPROM_content_valid = %d"), eeFlashId, EEPROM_content_valid); + return true; + } else { + printk(RED("eeFlashId(0x%x) isn't match with 0x%x!"), eeFlashId, consys_soc_chipid_get()); + return false; + } +} + +int _consys_check_adie_cfg(void) +{ + int ret = 0; + unsigned int hw_adie_type = 0; + unsigned int i = 0; + bool found = false; + + for (i = 0; i < AIDE_NUM_MAX; i++) { + if (conn_hw_env[i].valid) { + hw_adie_type = conn_hw_env[i].adie_id; + found = true; + break; + } + } + + if (found) { + printk(GRN("Adie Type: 0x%x"), hw_adie_type); + } else { + printk(RED("No Adie found!!!")); + ret = -1; + } + + return ret; +} + +void _consys_check_sku_cfg(void) +{ + unsigned int hw_sku_type; + + if (!one_adie_dbdc) { + if (adie_cfg_type == ADIE_TYPE_TWO) + hw_sku_type = 6000; + else + hw_sku_type = 7800; + + printk(GRN("SKU Type: %d"), hw_sku_type); + } else { + printk(GRN("SKU Type: One_Adie_DBDC")); + } +} + +int consys_plt_hw_init(void) +{ + unsigned int value = 0; + + value = CONSYS_REG_READ_BIT(REG_TOP_MISC_ADDR + TOP_MISC_RSRV_ALL1_3, (0x1 << 2)); + if (value != 0) + one_adie_dbdc = true; + else + one_adie_dbdc = false; + + if (_is_flash_content_valid()) { + FlashRead(MTD_WIFI_NM, (unsigned char*)&value, EEPROM_BAND0_STREAM_OFFSET, sizeof(value)); + tx_stream = ((value >> EEPROM_BAND0_STREAM_TX_BIT_OFFSET) & EEPROM_BAND0_STREAM_TX_MASK); + rx_stream = ((value >> EEPROM_BAND0_STREAM_RX_BIT_OFFSET) & EEPROM_BAND0_STREAM_RX_MASK); + + FlashRead(MTD_WIFI_NM, (unsigned char*)&value, EEPROM_LNA_PA_SELECT_OFFSET, sizeof(value)); + band0_pa_type = ((value >> EEPROM_LNA_PA_SELECT_BAND0_BIT_OFFSET) & EEPROM_LNA_PA_SELECT_BAND0_MASK); + band1_pa_type = ((value >> EEPROM_LNA_PA_SELECT_BAND1_BIT_OFFSET) & EEPROM_LNA_PA_SELECT_BAND1_MASK); + + if (one_adie_dbdc) { + adie_cfg_type = ADIE_TYPE_ONE; + } else { + if (tx_stream >= 2) { + adie_cfg_type = ADIE_TYPE_TWO; + } else { + adie_cfg_type = ADIE_TYPE_ONE; + } + } + pr_info("tx_stream = 0x%x, rx_stream = 0x%x, band0_pa_type = 0x%x, band1_pa_type = 0x%x\n", + tx_stream, rx_stream, band0_pa_type, band1_pa_type); + } else { + if (one_adie_dbdc) { + adie_cfg_type = ADIE_TYPE_ONE; + } else { + adie_cfg_type = ADIE_TYPE_TWO; + printk(RED("Flash content is empty, so use AX6000 configuration by default!")); + } + } + pr_info("adie_cfg_type = %d, one_adie_dbdc = %d\n", adie_cfg_type, one_adie_dbdc); + + return 0; +} + +int consys_xtal_ctrl_fast_mode(void) +{ + /* Setting fast mode to xtal control */ + CONSYS_SET_BIT(REG_TOP_MISC_ADDR + CONNSYS_MISC, (0x1 << 3)); + return 0; +} + +int consys_sw_reset_ctrl(bool bassert) +{ + /* Release CONNSYS software reset */ + if (bassert) { + CONSYS_REG_WRITE_MASK( + REG_TOP_RGU_ADDR + TOP_RGU_WDT_SWSYSRST, + 0x88800000, 0xff800000); + } else { + /* de-assert CONNSYS S/W reset */ + CONSYS_REG_WRITE_MASK( + REG_TOP_RGU_ADDR + TOP_RGU_WDT_SWSYSRST, + 0x88000000, 0xff800000); + } + + return 0; +} + +void consys_set_if_pinmux(bool enable) +{ + if (enable) { + /* Set PAD_WF*_HB* to GPIO mode by default. (Aux0) */ + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE9, 0x0, 0x77777700); + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE10, 0x0, 0x777777); + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE11, 0x0, 0x77777000); + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE12, 0x0, 0x77770); + + if (adie_cfg_type == ADIE_TYPE_TWO) { + /* Two_Adie + set pinmux for the interface between D-die and A-die (Aux1) + PAD_WF0_HB1(GPIO74) 0x0390[10:8] + PAD_WF0_HB2(GPIO75) 0x0390[14:12] + PAD_WF0_HB3(GPIO76) 0x0390[18:16] + PAD_WF0_HB4(GPIO77) 0x0390[22:20] + PAD_WF0_HB0(GPIO78) 0x0390[26:24] + PAD_WF0_HB5(GPIO80) 0x03A0[2:0] + PAD_WF0_HB6(GPIO81) 0x03A0[6:4] + PAD_WF0_HB7(GPIO82) 0x03A0[10:8] + PAD_WF0_HB8(GPIO83) 0x03A0[14:12] + PAD_WF1_HB1(GPIO91) 0x03B0[14:12] + PAD_WF1_HB2(GPIO92) 0x03B0[18:16] + PAD_WF1_HB3(GPIO93) 0x03B0[22:20] + PAD_WF1_HB4(GPIO94) 0x03B0[26:24] + PAD_WF1_HB0(GPIO95) 0x03B0[30:28] + PAD_WF1_HB5(GPIO97) 0x03C0[6:4] + PAD_WF1_HB6(GPIO98) 0x03C0[10:8] + PAD_WF1_HB7(GPIO99) 0x03C0[14:12] + PAD_WF1_HB8(GPIO100) 0x03C0[18:16] + */ + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE9, 0x1111100, 0x7777700); + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE10, 0x1111, 0x7777); + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE11, 0x11111000, 0x77777000); + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE12, 0x11110, 0x77770); + } else { + if (one_adie_dbdc) { + /* One_Adie_DB + set pinmux for the interface between D-die and A-die (Aux2) + PAD_WF0_HB1(GPIO74) 0x0390[10:8] + PAD_WF0_HB2(GPIO75) 0x0390[14:12] + PAD_WF0_HB3(GPIO76) 0x0390[18:16] + PAD_WF0_HB4(GPIO77) 0x0390[22:20] + PAD_WF0_HB0(GPIO78) 0x0390[26:24] + PAD_WF0_HB0_B(GPIO79) 0x0390[30:28] + PAD_WF0_HB5(GPIO80) 0x03A0[2:0] + PAD_WF0_HB6(GPIO81) 0x03A0[6:4] + PAD_WF0_HB7(GPIO82) 0x03A0[10:8] + PAD_WF0_HB8(GPIO83) 0x03A0[14:12] + PAD_WF0_HB9(GPIO84) 0x03A0[18:16] + PAD_WF0_HB10(GPIO85) 0x03A0[22:20] + */ + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE9, 0x22222200, 0x77777700); + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE10, 0x222222, 0x777777); + } else { + /* One_Adie_SB + set pinmux for the interface between D-die and A-die (Aux1) + PAD_WF1_HB1(GPIO91) 0x03B0[14:12] + PAD_WF1_HB2(GPIO92) 0x03B0[18:16] + PAD_WF1_HB3(GPIO93) 0x03B0[22:20] + PAD_WF1_HB4(GPIO94) 0x03B0[26:24] + PAD_WF1_HB0(GPIO95) 0x03B0[30:28] + PAD_WF1_HB5(GPIO97) 0x03C0[6:4] + PAD_WF1_HB6(GPIO98) 0x03C0[10:8] + PAD_WF1_HB7(GPIO99) 0x03C0[14:12] + PAD_WF1_HB8(GPIO100) 0x03C0[18:16] + */ + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE11, 0x11111000, 0x77777000); + CONSYS_REG_WRITE_MASK(REG_GPIO_BASE_ADDR + GPIO_MODE12, 0x11110, 0x77770); + } + } + /* Set pinmux driving to 4mA + 2mA: [000] + 4mA: [001] + 6mA: [010] + 8mA: [011] + 10mA: [100] + 12mA: [101] + 14mA: [110] + 16mA: [111] + PAD_WF0_HB1 0x0000[17:15] + PAD_WF0_HB2 0x0000[20:18] + PAD_WF0_HB3 0x0000[23:21] + PAD_WF0_HB4 0x0000[26:24] + PAD_WF0_HB0 0x0000[8:6] + PAD_WF0_HB0_B 0x0000[11:9] + PAD_WF0_HB5 0x0000[29:27] + PAD_WF0_HB6 0x0010[2:0] + PAD_WF0_HB7 0x0010[5:3] + PAD_WF0_HB8 0x0010[8:6] + PAD_WF0_HB9 0x0010[11:9] + PAD_WF0_HB10 0x0000[14:12] + PAD_WF0_TOP_CLK 0x0010[14:12] + PAD_WF0_TOP_DATA 0x0010[17:15] + + PAD_WF1_HB1 0x0000[14:12] + PAD_WF1_HB2 0x0000[17:15] + PAD_WF1_HB3 0x0000[20:18] + PAD_WF1_HB4 0x0000[23:21] + PAD_WF1_HB0 0x0000[8:6] + PAD_WF1_HB5 0x0000[26:24] + PAD_WF1_HB6 0x0000[29:27] + PAD_WF1_HB7 0x0010[2:0] + PAD_WF1_HB8 0x0010[5:3] + PAD_WF1_TOP_CLK 0x0010[8:6] + PAD_WF1_TOP_DATA 0x0010[11:9] + */ + CONSYS_REG_WRITE_MASK(REG_IOCFG_TR_ADDR + IOCFG_TR_DRV_CFG0, 0x9249240, 0x3FFFFFC0); + CONSYS_REG_WRITE_MASK(REG_IOCFG_TR_ADDR + IOCFG_TR_DRV_CFG1, 0x9249, 0x3FFF); + CONSYS_REG_WRITE_MASK(REG_IOCFG_TL_ADDR + IOCFG_TL_DRV_CFG0, 0x9249040, 0x3FFFF1C0); + CONSYS_REG_WRITE_MASK(REG_IOCFG_TL_ADDR + IOCFG_TL_DRV_CFG1, 0x249, 0xFFF); + } +} + +int consys_tx_rx_bus_slp_prot_ctrl(bool enable) +{ + int check; + + if (enable) { + /* conn2ap/ap2conn slpprot disable */ + /* Turn off AP2CONN AHB RX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, 0x0, 0x10000); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, + 24, 0x0, 100, 500, check); + if (check != 0) + pr_err("Polling AP2CONN AHB RX bus sleep protect turn off fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT)); + + /* Turn off AP2CONN AHB TX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, 0x0, 0x1); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, + 4, 0x0, 100, 500, check); + if (check != 0) + pr_err("Polling AP2CONN AHB TX bus sleep protect turn off fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT)); + + /* Turn off CONN2AP AXI RX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, 0x0, 0x10000); + /* Turn off CONN2AP AXI TX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, 0x0, 0x1); + + /* Wait 900us (apply this for CONNSYS XO clock ready) */ + udelay(900); + } else { + /* Turn on AP2CONN AHB TX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, 0x1, 0x1); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, + 4, 0x1, 100, 500, check); + if (check != 1) + pr_err("Polling AP2CONN AHB TX bus sleep protect turn on fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT)); + + /* Turn on AP2CONN AHB RX bus sleep protec */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, 0x1, 0x10000); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT, + 24, 0x1, 100, 500, check); + if (check !=1) + pr_err("Polling AP2CONN AHB RX bus sleep protect turn on fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + AP2CONN_GALS_SLPPROT)); + + /* Turn on CONN2AP AXI TX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, 0x1, 0x1); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, + 4, 0x1, 100, 500, check); + if (check != 1) + pr_err("Polling CONN2AP AXI TX bus sleep protect turn on fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT)); + + /* Turn on CONN2AP AXI RX bus sleep protect */ + CONSYS_REG_WRITE_MASK(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, 0x1, 0x10000); + CONSYS_REG_BIT_POLLING(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT, + 24, 0x1, 100, 500, check); + if (check != 1) + pr_err("Polling CONN2AP AXI RX bus sleep protect turn on fail! CR Value = 0x%08x\n", + CONSYS_REG_READ(REG_INFRACFG_AO_ADDR + CONN2AP_GALS_SLPPROT)); + + /* wait 1us*/ + udelay(1); + } + + return 0; +} + +int _consys_polling_chipid_int(unsigned int retry, unsigned int sleep_ms) +{ + unsigned int count = retry + 1; + unsigned int consys_hw_ver = consys_get_hw_ver(); + unsigned int hw_ver = 0; + + while (--count > 0) { + hw_ver = CONSYS_REG_READ(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_CFG_IP_VERSION); + if ((hw_ver >= consys_hw_ver) && (hw_ver != 0xdeadfeed)) + break; + msleep(sleep_ms); + } + + if (count == 0) { + pr_err("Read CONNSYS HW IP version fail. Expect 0x%x but get 0x%x\n", consys_hw_ver, hw_ver); + return -1; + } else { + pr_info("Read CONNSYS HW IP version successfully! (0x%08x)\n", hw_ver); + } + + return 0; +} + +int consys_polling_chipid(void) +{ + return _consys_polling_chipid_int(10, 1); +} + +int consys_bus_clock_ctrl(enum consys_drv_type drv_type, unsigned int bus_clock) +{ + static unsigned int conninfra_bus_clock_wpll_state = 0; + unsigned int wpll_state = conninfra_bus_clock_wpll_state; + bool wpll_switch = false; + + /* switch conn_infra bus clock pll ready check to pll-1 */ + if (bus_clock & CONNINFRA_BUS_CLOCK_WPLL) { + if (conninfra_bus_clock_wpll_state == 0) { + CONSYS_SET_BIT(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS, (0x1 << 29)); + wpll_switch = true; + } + conninfra_bus_clock_wpll_state |= (0x1 << drv_type); + } + pr_info("drv=[%d] conninfra_bus_clock_wpll=[%u]->[%u] %s\n", + drv_type, wpll_state, conninfra_bus_clock_wpll_state, (wpll_switch ? "enable" : "")); + + return 0; +} + +int consys_emi_set_remapping_reg(void) +{ + struct consys_emi_addr_info *addr_info = emi_mng_get_phy_addr(); + + /* 0x1806_01C4[19:0], ap_emi_base[19:0] = TBD (related to emi) + 0x1806_01D4[19:0], wf_ap_peri_base[19:0] = 0x0_1100 (un-related to emi) + */ + if (addr_info->emi_ap_phy_base != 0) + CONSYS_REG_WRITE_OFFSET_RANGE(REG_CONN_HOST_CSR_TOP_ADDR + CONN2AP_REMAP_MCU_EMI, + addr_info->emi_ap_phy_base, 0, 16, 20); + /* + CONSYS_REG_WRITE_OFFSET_RANGE(REG_CONN_HOST_CSR_TOP_ADDR + CONN2AP_REMAP_WF_PERI, + 0x300D0000, 0, 16, 20); + */ + + return 0; +} + +int consys_emi_set_region_protection(void) +{ + struct consys_emi_addr_info *addr_info = emi_mng_get_phy_addr(); + + /* set infra top emi address range */ + if (addr_info->emi_ap_phy_base != 0) { + CONSYS_REG_WRITE(REG_CONN_INFRA_BUS_CR_ADDR + CONN2AP_EMI_PATH_ADDR_START, + addr_info->emi_ap_phy_base); + + if (addr_info->emi_ap_phy_size != 0) + CONSYS_REG_WRITE(REG_CONN_INFRA_BUS_CR_ADDR + CONN2AP_EMI_PATH_ADDR_END, + addr_info->emi_ap_phy_base + addr_info->emi_ap_phy_size); + } + + return 0; +} + +int connsys_d_die_cfg(void) +{ + unsigned int efuse; + + efuse = CONSYS_REG_READ(REG_CONN_INFRA_CFG_ADDR + EFUSE); + pr_info("D-die efuse: 0x%08x\n", efuse); + + return 0; +} + +int connsys_conninfra_sysram_hw_ctrl(void) +{ + /* conn_infra sysram hw control setting -> disable hw power down */ + CONSYS_REG_WRITE(REG_CONN_INFRA_RGU_ADDR + SYSRAM_HWCTL_PDN, 0x0); + + /* conn_infra sysram hw control setting -> enable hw sleep */ + CONSYS_REG_WRITE(REG_CONN_INFRA_RGU_ADDR + SYSRAM_HWCTL_SLP, 0x1); + + return 0; +} + +int connsys_spi_master_cfg(void) +{ + /* wt_slp CR for A-die ck_en/wake_en control */ + /* + RFSPI #0 RFSPI #1 + WF_CK_ADDR 0x18005070[11:0] 0x18085070[11:0] 0xA04 + WF_B1_CK_ADDR 0x18005070[27:16] 0x18085070[27:16] 0xAF4 + WF_WAKE_ADDR 0x18005074[11:0] 0x18085074[11:0] 0x090 + WF_B1_WAKE_ADDR 0x18005074[27:16] 0x18085074[27:16] 0x0A0 + WF_ZPS_ADDR 0x18005078[11:0] 0x18085078[11:0] 0x08C + WF_B1_ZPS_ADDR 0x18005078[27:16] 0x18085078[27:16] 0x09C + TOP_CK_ADDR 0x18005084[11:0] 0x18085084[11:0] 0xA00 + WF_B0_CMD_ADDR 0x1800508c[11:0] 0x1808508c[11:0] 0x0F0 + WF_B1_CMD_ADDR 0x18005090[11:0] 0x18085090[11:0] 0x0F4 + */ + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_CK_ADDR, 0xAF40A04, 0xFFF0FFF); + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_WAKE_ADDR, 0x0A00090, 0xFFF0FFF); + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_ZPS_ADDR, 0x09C008C, 0xFFF0FFF); + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_TOP_CK_ADDR, 0xA00, 0xFFF); + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_B0_CMD_ADDR, 0x0F0, 0xFFF); + CONSYS_REG_WRITE_MASK(REG_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_B1_CMD_ADDR, 0x0F4, 0xFFF); + CONSYS_REG_WRITE_MASK(REG_INST2_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_CK_ADDR, 0xAF40A04, 0xFFF0FFF); + CONSYS_REG_WRITE_MASK(REG_INST2_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_WAKE_ADDR, 0x0A00090, 0xFFF0FFF); + CONSYS_REG_WRITE_MASK(REG_INST2_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_ZPS_ADDR, 0x09C008C, 0xFFF0FFF); + CONSYS_REG_WRITE_MASK(REG_INST2_CONN_WT_SLP_CTL_REG_ADDR + WB_TOP_CK_ADDR, 0xA00, 0xFFF); + CONSYS_REG_WRITE_MASK(REG_INST2_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_B0_CMD_ADDR, 0x0F0, 0xFFF); + CONSYS_REG_WRITE_MASK(REG_INST2_CONN_WT_SLP_CTL_REG_ADDR + WB_WF_B1_CMD_ADDR, 0x0F4, 0xFFF); + + return 0; +} + +static int consys_spi_read_nolock(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data) +{ + int check = 0; + unsigned long rf_spi_addr = 0; + const struct spi_op *op = NULL; + unsigned char adie_idx = ((subsystem & 0xF0) >> 4); //0: one adie, 1: two adie + unsigned char subsystem_idx = (subsystem & 0xF); + + if (!data) { + pr_err("invalid data ptr\n"); + return CONNINFRA_SPI_OP_FAIL; + } + + op = &spi_op_array[subsystem_idx]; + if (adie_idx != 0) + rf_spi_addr = REG_INST2_CONN_RF_SPI_MST_REG_ADDR; + else + rf_spi_addr = REG_CONN_RF_SPI_MST_REG_ADDR; + + /* Read action: + * 1. Polling busy_cr[polling_bit] should be 0 + * 2. Write addr_cr with data being {read_addr_format | addr[11:0]} + * 3. Trigger SPI by writing write_data_cr as 0 + * 4. Polling busy_cr[polling_bit] as 0 + * 5. Read data_cr[data_mask] + */ + + CONSYS_REG_BIT_POLLING(rf_spi_addr + op->busy_cr, op->polling_bit, 0, 100, 500, check); + if (check != 0) { + pr_err("[%d][STEP1] polling 0x%08lx bit %d fail. Value=0x%08x\n", + subsystem, rf_spi_addr + op->busy_cr, op->polling_bit, + CONSYS_REG_READ(rf_spi_addr + op->busy_cr)); + return CONNINFRA_SPI_OP_FAIL; + } + + CONSYS_REG_WRITE(rf_spi_addr + op->addr_cr, (op->read_addr_format | addr)); + CONSYS_REG_WRITE(rf_spi_addr + op->write_data_cr, 0); + + CONSYS_REG_BIT_POLLING(rf_spi_addr + op->busy_cr, op->polling_bit, 0, 100, 500, check); + if (check != 0) { + pr_err("[%d][STEP4] polling 0x%08lx bit %d fail. Value=0x%08x\n", + subsystem, rf_spi_addr + op->busy_cr, + op->polling_bit, CONSYS_REG_READ(rf_spi_addr + op->busy_cr)); + return CONNINFRA_SPI_OP_FAIL; + } + + check = CONSYS_REG_READ_BIT(rf_spi_addr + op->read_data_cr, op->read_data_mask); + *data = check; + + return 0; +} + +static int consys_spi_write_nolock(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data) +{ + int check = 0; + unsigned long rf_spi_addr = 0; + const struct spi_op *op = NULL; + unsigned char adie_idx = ((subsystem & 0xF0) >> 4); //0: one adie, 1: two adie + unsigned char subsystem_idx = (subsystem & 0xF); + + op = &spi_op_array[subsystem_idx]; + if (adie_idx != 0) + rf_spi_addr = REG_INST2_CONN_RF_SPI_MST_REG_ADDR; + else + rf_spi_addr = REG_CONN_RF_SPI_MST_REG_ADDR; + + /* Write action: + * 1. Wait busy_cr[polling_bit] as 0 + * 2. Write addr_cr with data being {write_addr_format | addr[11:0] + * 3. Write write_data_cr ad data + * 4. Wait busy_cr[polling_bit] as 0 + */ + + CONSYS_REG_BIT_POLLING(rf_spi_addr + op->busy_cr, op->polling_bit, 0, 100, 500, check); + if (check != 0) { + pr_err("[%d][STEP1] polling 0x%08lx bit %d fail. Value=0x%08x\n", + subsystem, rf_spi_addr + op->busy_cr, + op->polling_bit, CONSYS_REG_READ(rf_spi_addr + op->busy_cr)); + return CONNINFRA_SPI_OP_FAIL; + } + + CONSYS_REG_WRITE(rf_spi_addr + op->addr_cr, (op->write_addr_format | addr)); + CONSYS_REG_WRITE(rf_spi_addr + op->write_data_cr, data); + + check = 0; + CONSYS_REG_BIT_POLLING(rf_spi_addr + op->busy_cr, op->polling_bit, 0, 100, 500, check); + if (check != 0) { + pr_err("[%d][STEP4] polling 0x%08lx bit %d fail. Value=0x%08x\n", + subsystem, rf_spi_addr + op->busy_cr, + op->polling_bit, CONSYS_REG_READ(rf_spi_addr + op->busy_cr)); + return CONNINFRA_SPI_OP_FAIL; + } + + pr_info("addr = 0x%04x, val = 0x%08x\n", addr, data); + + return 0; +} + +static int consys_sema_acquire(enum conn_semaphore_type index) +{ + if (CONSYS_REG_READ_BIT((REG_CONN_SEMAPHORE_ADDR + CONN_SEMA00_M2_OWN_STA + index*4), 0x1) == 0x1) { + return CONN_SEMA_GET_SUCCESS; + } else { + return CONN_SEMA_GET_FAIL; + } +} + +int consys_sema_acquire_timeout(unsigned int index, unsigned int usec) +{ + int i; + + if (index >= CONN_SEMA_NUM_MAX) { + pr_err("wrong index: %d\n", index); + return CONN_SEMA_GET_FAIL; + } + + for (i = 0; i < usec; i++) { + if (consys_sema_acquire(index) == CONN_SEMA_GET_SUCCESS) { + return CONN_SEMA_GET_SUCCESS; + } + udelay(1); + } + pr_err("Get semaphore 0x%x timeout, dump status:\n", index); + pr_err("M0:[0x%x] M1:[0x%x] M2:[0x%x] M3:[0x%x] M4:[0x%x] M5:[0x%x] M6:[0x%x] M7:[0x%x]\n", + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M0_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M1_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M2_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M3_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M4_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M5_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M6_STA_REP), + CONSYS_REG_READ(REG_CONN_SEMAPHORE_ADDR + CONN_SEMA_OWN_BY_M7_STA_REP)); + + return CONN_SEMA_GET_FAIL; +} + +void consys_sema_release(unsigned int index) +{ + if (index >= CONN_SEMA_NUM_MAX) { + pr_err("wrong index: %d\n", index); + return; + } + + CONSYS_REG_WRITE((REG_CONN_SEMAPHORE_ADDR + CONN_SEMA00_M2_OWN_REL + index*4), 0x1); +} + +int consys_spi_read(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data) +{ + int ret; + + /* Get semaphore before read */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("[SPI READ] Require semaphore fail\n"); + return CONNINFRA_SPI_OP_FAIL; + } + + ret = consys_spi_read_nolock(subsystem, addr, data); + + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return ret; +} + +int consys_spi_write(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data) +{ + int ret; + + /* Get semaphore before read */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("[SPI WRITE] Require semaphore fail\n"); + return CONNINFRA_SPI_OP_FAIL; + } + + ret = consys_spi_write_nolock(subsystem, addr, data); + + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + return ret; +} + +static void consys_spi_write_offset_range_nolock( + enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int value, + unsigned int reg_offset, unsigned int value_offset, unsigned int size) +{ + unsigned int data = 0, data2; + unsigned int reg_mask; + int ret; + + pr_info("[%s] addr=0x%04x value=0x%08x reg_offset=%d value_offset=%d size=%d\n", + g_spi_system_name[subsystem], addr, value, reg_offset, value_offset, size); + + value = (value >> value_offset); + value = GET_BIT_RANGE(value, size, 0); + value = (value << reg_offset); + ret = consys_spi_read_nolock(subsystem, addr, &data); + if (ret) { + pr_err("[%s] Get 0x%08x error, ret=%d\n", + g_spi_system_name[subsystem], addr, ret); + return; + } + + reg_mask = GENMASK(reg_offset + size - 1, reg_offset); + data2 = data & (~reg_mask); + data2 = (data2 | value); + consys_spi_write_nolock(subsystem, addr, data2); + + pr_info("[%s] Write CR:0x%08x from 0x%08x to 0x%08x\n", + g_spi_system_name[subsystem], addr, data, data2); +} + +int consys_spi_write_offset_range( + enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int value, + unsigned int reg_offset, unsigned int value_offset, unsigned int size) +{ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("[SPI READ] Require semaphore fail\n"); + return CONNINFRA_SPI_OP_FAIL; + } + consys_spi_write_offset_range_nolock(subsystem, addr, value, reg_offset, value_offset, size); + + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return 0; +} + +/***************************************************************************** +* FUNCTION +* connsys_a_die_efuse_read +* DESCRIPTION +* Read a-die efuse +* PARAMETERS +* efuse_addr: read address +* RETURNS +* int +* 0: fail, efuse is invalid +* 1: success, efuse is valid +*****************************************************************************/ +static int connsys_a_die_efuse_read_nolock( + enum sys_spi_subsystem subsystem, unsigned int efuse_ctrl, unsigned int efuse_addr, + unsigned int *data0, unsigned int *data1, unsigned int *data2, unsigned int *data3) +{ + int ret = 0; + int retry = 0; + int ret0, ret1, ret2, ret3; + unsigned int efuse_block_sel; + + if (data0 == NULL || data1 == NULL || data2 == NULL || data3 == NULL) { + pr_err("invalid parameter (%p, %p, %p, %p)\n", + data0, data1, data2, data3); + return 0; + } + + switch (efuse_ctrl) { + case ATOP_EFUSE_CTRL_1: + efuse_block_sel = 0x1; + break; + + case ATOP_EFUSE_CTRL_2: + efuse_block_sel = 0x2; + break; + + case ATOP_EFUSE_CTRL_3: + efuse_block_sel = 0x4; + break; + + case ATOP_EFUSE_CTRL_4: + efuse_block_sel = 0x8; + break; + + default: + pr_err("No support for efuse block No. = %d\n", efuse_ctrl); + return 0; + break; + } + + /* select Efuse block */ + consys_spi_write_nolock(subsystem, ATOP_RG_EFUSE_CFG5, efuse_block_sel); + + /* Efuse control clear, clear Status /trigger + * Address: ATOP EFUSE_CTRL_write_efsrom_kick_and_read_kick_busy_flag (0x108[30]) + * Data: 1'b0 + * Action: TOPSPI_WR + */ + consys_spi_read_nolock(subsystem, efuse_ctrl, &ret); + ret &= ~(0x1 << 30); + consys_spi_write_nolock(subsystem, efuse_ctrl, ret); + + /* Efuse Read 1st 16byte + * Address: + * ATOP EFUSE_CTRL_efsrom_mode (0x108[7:6]) = 2'b00 + * ATOP EFUSE_CTRL_efsrom_ain (0x108[25:16]) = efuse_addr (0) + * ATOP EFUSE_CTRL_write_efsrom_kick_and_read_kick_busy_flag (0x108[30]) = 1'b1 + * Action: TOPSPI_WR + */ + consys_spi_read_nolock(subsystem, efuse_ctrl, &ret); + ret &= ~(0x43FF00C0); + ret |= (0x1 << 30); + ret |= ((efuse_addr << 16) & 0x3FF0000); + consys_spi_write_nolock(subsystem, efuse_ctrl, ret); + + /* Polling EFUSE busy = low + * (each polling interval is "30us" and polling timeout is 2ms) + * Address: + * ATOP EFUSE_CTRL_write_efsrom_kick_and_read_kick_busy_flag (0x108[30]) = 1'b0 + * Action: TOPSPI_Polling + */ + consys_spi_read_nolock(subsystem, efuse_ctrl, &ret); + while ((ret & (0x1 << 30)) != 0 && retry < 70) { + retry++; + udelay(30); + consys_spi_read_nolock(subsystem, efuse_ctrl, &ret); + } + if ((ret & (0x1 << 30)) != 0) { + pr_err("EFUSE busy, retry failed(%d)\n", retry); + } + + /* Check efuse_valid & return + * Address: ATOP EFUSE_CTRL_csri_efsrom_dout_vld_sync_1_ (0x108[29]) + * Action: TOPSPI_RD + */ + /* if (efuse_valid == 1'b1) + * Read Efuse Data to global var + */ + consys_spi_read_nolock(subsystem, efuse_ctrl, &ret); + if (((ret & (0x1 << 29)) >> 29) == 1) { + ret0 = consys_spi_read_nolock(subsystem, ATOP_EFUSE_RDATA0, data0); + ret1 = consys_spi_read_nolock(subsystem, ATOP_EFUSE_RDATA1, data1); + ret2 = consys_spi_read_nolock(subsystem, ATOP_EFUSE_RDATA2, data2); + ret3 = consys_spi_read_nolock(subsystem, ATOP_EFUSE_RDATA3, data3); + + pr_info("efuse = [0x%08x, 0x%08x, 0x%08x, 0x%08x]\n", *data0, *data1, *data2, *data3); + if (ret0 || ret1 || ret2 || ret3) + pr_err("efuse read error: [%d, %d, %d, %d]\n", ret0, ret1, ret2, ret3); + ret = 1; + } else { + pr_err("EFUSE is invalid\n"); + ret = 0; + } + + return ret; +} + +static int _connsys_a_die_thermal_cal(enum sys_spi_subsystem subsystem) +{ + int efuse_valid = 0; + unsigned int efuse0 = 0, efuse1 = 0, efuse2 = 0, efuse3 = 0; + + /* thernal efuse data in 7976&7975 in EFUSE2 */ + efuse_valid = connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_THADC_ANALOG, + &efuse0, &efuse1, &efuse2, &efuse3); + //if (efuse_valid) { + if ((efuse0 & (0x1 << 7))) { + consys_spi_write_offset_range_nolock(subsystem, ATOP_RG_TOP_THADC_BG, efuse0, 12, 3, 4); + consys_spi_write_offset_range_nolock(subsystem, ATOP_RG_TOP_THADC_00, efuse0, 23, 0, 3); + } + //} + + efuse_valid = connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_THADC_SLOP, + &efuse0, &efuse1, &efuse2, &efuse3); + //if (efuse_valid) { + if((efuse0 & (0x1 << 7))) { + consys_spi_write_offset_range_nolock(subsystem, ATOP_RG_TOP_THADC_00, efuse0, 26, 5, 2); + } + //} + + return 0; +} + +static int _connsys_a_die_xtal_trim_7976(enum sys_spi_subsystem subsystem) +{ + unsigned int efuse0 = 0, efuse1 = 0, efuse2 = 0, efuse3 = 0; + int c1c2_trim_result_ax_80m = 0, c1c2_trim_result_ax_40m = 0; + unsigned int cbtop_strap_rdata = 0, xtal_strap_mode = 0, adie_rdata = 0, value = 0; + + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_XTAL_TRIM_FLOW, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 < 1))) { + /* C1C2 80M AX */ + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_XTAL_CR_C1_SEL_AXM_80M_OSC, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 < 7)) == 0) { + c1c2_trim_result_ax_80m = 64; + } else { + c1c2_trim_result_ax_80m = (efuse0 & 0x7F); + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_XTAL_CR_C1_SEL_AXM_TRIM1_80M_OSC, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 < 7)) == 1) { + if ((efuse0 & (0x1 < 6)) == 0) { + c1c2_trim_result_ax_80m = c1c2_trim_result_ax_80m + (efuse0 & 0x3F); + } else { + c1c2_trim_result_ax_80m = c1c2_trim_result_ax_80m - (efuse0 & 0x3F); + } + + if (c1c2_trim_result_ax_80m > 127) + c1c2_trim_result_ax_80m = 127; + else if (c1c2_trim_result_ax_80m < 0) + c1c2_trim_result_ax_80m = 0; + } + } + + /* C1C2 40M AX */ + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_XTAL_CR_C1_SEL_AXM_40M_OSC, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 < 7)) == 0) { + c1c2_trim_result_ax_40m = 64; + } else { + c1c2_trim_result_ax_40m = (efuse0 & 0x7F); + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_XTAL_CR_C1_SEL_AXM_TRIM1_40M_OSC, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 < 7)) == 1) { + if ((efuse0 & (0x1 < 6)) == 0) { + c1c2_trim_result_ax_40m = c1c2_trim_result_ax_40m + (efuse0 & 0x3F); + } else { + c1c2_trim_result_ax_40m = c1c2_trim_result_ax_40m - (efuse0 & 0x3F); + } + + if (c1c2_trim_result_ax_40m > 127) + c1c2_trim_result_ax_40m = 127; + else if (c1c2_trim_result_ax_40m < 0) + c1c2_trim_result_ax_40m = 0; + } + } + + /* Update trim value to C1 and C2 */ + consys_spi_read_nolock(subsystem, ATOP_RG_STRAP_PIN_IN, &cbtop_strap_rdata); + xtal_strap_mode = ((cbtop_strap_rdata & 0x70) >> 4); + if ((xtal_strap_mode == 0x0) || (xtal_strap_mode == 0x2)) { //80m osc + /* C1 */ + consys_spi_read_nolock(subsystem, 0x654, &adie_rdata); + value = (adie_rdata & 0xFFFFFF) | ((c1c2_trim_result_ax_80m & 0xFF) << 24); + consys_spi_write_nolock(subsystem, 0x654, value); + + /* C2 */ + consys_spi_read_nolock(subsystem, 0x658, &adie_rdata); + value = (adie_rdata & 0xFFFFFF) | ((c1c2_trim_result_ax_80m & 0xFF) << 24); + consys_spi_write_nolock(subsystem, 0x658, value); + } else if ((xtal_strap_mode == 0x3) || (xtal_strap_mode == 0x4) || (xtal_strap_mode == 0x6)) { //40m osc + /* C1 */ + consys_spi_read_nolock(subsystem, 0x654, &adie_rdata); + value = (adie_rdata & 0xFF00FFFF) | ((c1c2_trim_result_ax_40m & 0xFF) << 16); + consys_spi_write_nolock(subsystem, 0x654, value); + + /* C2 */ + consys_spi_read_nolock(subsystem, 0x658, &adie_rdata); + value = (adie_rdata & 0xFF00FFFF) | ((c1c2_trim_result_ax_40m & 0xFF) << 16); + consys_spi_write_nolock(subsystem, 0x658, value); + } + } + + return 0; +} + +static int _connsys_a_die_sw_cntl(enum sys_spi_subsystem subsystem, unsigned char adie_idx) +{ + if (conn_hw_env[adie_idx].valid && (conn_hw_env[adie_idx].adie_id == 0x7976)) { + if ((conn_hw_env[adie_idx].adie_hw_version == 0x8A00) + || (conn_hw_env[adie_idx].adie_hw_version == 0x8A10) + || (conn_hw_env[adie_idx].adie_hw_version == 0x8B00)){ + consys_spi_write_nolock(subsystem, ATOP_RG_TOP_THADC_00, 0x4A563B00); + consys_spi_write_nolock(subsystem, ATOP_RG_XO_01, 0x1D59080F); + consys_spi_write_nolock(subsystem, ATOP_RG_XO_03, 0x34C00FE0); + } else { + consys_spi_write_nolock(subsystem, ATOP_RG_TOP_THADC_00, 0x4A563B00); + consys_spi_write_nolock(subsystem, ATOP_RG_XO_01, 0x1959F80F); + consys_spi_write_nolock(subsystem, ATOP_RG_XO_03, 0x34D00FE0); + } + } + + return 0; +} + +int _connsys_a_die_cfg_7976(unsigned char adie_idx) +{ + int check; + unsigned int adie_chip_id = 0x0; + unsigned char subsystem = 0; + + if (adie_idx == 1) + subsystem = SYS_SPI_2ND_ADIE_TOP; + else + subsystem = SYS_SPI_TOP; + + /* release D Die to A Die Digital reset_b */ + if (adie_idx == 1) + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x4); + else + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x1); + + /* Get semaphore once */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("Require semaphore fail\n"); + return -1; + } + + /* read a-die ID */ + check = consys_spi_read_nolock(subsystem, ATOP_CHIP_ID, &adie_chip_id); + if (check) { + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + pr_err("Get ATOP_CHIP_ID fail, check = %d\n", check); + return -1; + } + + /* enable TOPDIG CK */ + check = consys_spi_write_nolock(subsystem, ATOP_TOP_CLK_EN, 0xFFFFFFFF); + + /* config WRI CK select */ + if (one_adie_dbdc) + check = consys_spi_write_nolock(subsystem, ATOP_RG_WRI_CK_SELECT, 0x1C); + + /* Thermal Cal (TOP) */ + _connsys_a_die_thermal_cal(subsystem); + + /* XTAL TRIM */ + _connsys_a_die_xtal_trim_7976(subsystem); + + /* SW control part */ + _connsys_a_die_sw_cntl(subsystem, adie_idx); + + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return 0; +} + +static int _connsys_a_die_xtal_trim_7975(enum sys_spi_subsystem subsystem) +{ + unsigned int efuse0 = 0, efuse1 = 0, efuse2 = 0, efuse3 = 0; + unsigned int trim_result = 0, value = 0; + int ret = 0; + + ret = connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_7975_XTAL_TRIM_FLOW, + &efuse0, &efuse1, &efuse2, &efuse3); + if (((efuse0 & 0x1) == 0) || (ret == 0)) + return 0; + + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_7975_XTAL_CALIBRATION, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 << 7))) { + trim_result = (efuse0 & 0x7F); + trim_result = (trim_result & 0x7F); + } + + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_7975_XTAL_TRIM2_COMPENSATION, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 << 7))){ + if ((efuse0 & (0x1 << 6))) + trim_result -= (efuse0 & 0x3F); + else + trim_result += (efuse0 & 0x3F); + trim_result = (trim_result & 0x7F); + } + + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_7975_XTAL_TRIM3_COMPENSATION, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 << 7))){ + if ((efuse0 & (0x1 << 6))) + trim_result -= (efuse0 & 0x3F); + else + trim_result += (efuse0 & 0x3F); + trim_result = (trim_result & 0x7F); + } + + connsys_a_die_efuse_read_nolock(subsystem, ATOP_EFUSE_CTRL_2, ATOP_7975_XTAL_TRIM4_COMPENSATION, + &efuse0, &efuse1, &efuse2, &efuse3); + if ((efuse0 & (0x1 << 7))){ + if ((efuse0 & (0x1 << 6))) + trim_result -= (efuse0 & 0x3F); + else + trim_result += (efuse0 & 0x3F); + trim_result = (trim_result & 0x7F); + } + + /* Update Trim Value to C1 and C2*/ + /* Step 1 */ + consys_spi_read_nolock(subsystem, ATOP_7975_CR_C1_C2_A94, &value); + value = ((value & 0xf8080fff) | ((trim_result << 20) | (trim_result << 12))); + consys_spi_write_nolock(subsystem, ATOP_7975_CR_C1_C2_A94, value); + + /* Step 2 */ + consys_spi_read_nolock(subsystem, ATOP_7975_CR_C1_C2_A18, &value); + if(value & (1<<29)){ + consys_spi_read_nolock(subsystem, ATOP_7975_CR_C1_C2_A84, &value); + value = (value & 0x7fffffff); + consys_spi_write_nolock(subsystem, ATOP_7975_CR_C1_C2_A84, value); + } + + /* Step 3 */ + consys_spi_read_nolock(subsystem, ATOP_7975_CR_C1_C2_AA4, &value); + value = ((value & 0xfffeffff) | 0x10000); + consys_spi_write_nolock(subsystem, ATOP_7975_CR_C1_C2_AA4, value); + + return 0; +} + + +static int _connsys_a_die_form_patch_7975(enum sys_spi_subsystem subsystem) +{ + pr_info("Form 7975 adie Patch\n"); + + /* disable CAL LDO and fine tune RFDIG LDO, 20191218 */ + consys_spi_write_nolock(subsystem, 0x348, 0x00000002); + + /* disable CAL LDO and fine tune RFDIG LDO, 20191218 */ + consys_spi_write_nolock(subsystem, 0x378, 0x00000002); + + /* disable CAL LDO and fine tune RFDIG LDO, 20191218 */ + consys_spi_write_nolock(subsystem, 0x3A8, 0x00000002); + + /* disable CAL LDO and fine tune RFDIG LDO, 20191218 */ + consys_spi_write_nolock(subsystem, 0x3D8, 0x00000002); + + /* set CKA driving and filter */ + consys_spi_write_nolock(subsystem, 0xA1C, 0x30000AAA); + + /* set CKB LDO to 1.4V */ + consys_spi_write_nolock(subsystem, 0xA84, 0x8470008A); + + /* turn on SX0 LTBUF */ + consys_spi_write_nolock(subsystem, 0x074, 0x00000002); + + /* CK_BUF_SW_EN=1 (all buf in manual mode.) */ + consys_spi_write_nolock(subsystem, 0xAA4, 0x01001FC0); + + /* BT mode/WF normal mode 32?™h=00000005 */ + consys_spi_write_nolock(subsystem, 0x070, 0x00000005); + + /* BG thermal sensor offset update */ + consys_spi_write_nolock(subsystem, 0x344, 0x00000088); + + /* BG thermal sensor offset update */ + consys_spi_write_nolock(subsystem, 0x374, 0x00000088); + + /* BG thermal sensor offset update */ + consys_spi_write_nolock(subsystem, 0x3A4, 0x00000088); + + /* BG thermal sensor offset update */ + consys_spi_write_nolock(subsystem, 0x3D4, 0x00000088); + + /* set WCON VDD IPTAT to "0000" */ + consys_spi_write_nolock(subsystem, 0xA80, 0x44D07000); + + /* change back LTBUF SX3 drving to default value, 20191113 */ + consys_spi_write_nolock(subsystem, 0xA88, 0x3900AAAA); + + /* SM input cap off */ + consys_spi_write_nolock(subsystem, 0x2C4, 0x00000000); + + /* set CKB driving and filter */ + consys_spi_write_nolock(subsystem, 0x2C8, 0x00000072); + + return 0; +} + +int _connsys_a_die_cfg_7975(unsigned char adie_idx) +{ + int check; + unsigned int adie_chip_id = 0x0; + unsigned int value = 0x0; + unsigned char subsystem = 0; + + if (adie_idx == 1) + subsystem = SYS_SPI_2ND_ADIE_TOP; + else + subsystem = SYS_SPI_TOP; + + /* release D Die to A Die Digital reset_b */ + if (adie_idx == 1) + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x4); + else + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x1); + + /* Get semaphore once */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("Require semaphore fail\n"); + return -1; + } + + /* read a-die ID */ + check = consys_spi_read_nolock(subsystem, ATOP_CHIP_ID, &adie_chip_id); + if (check) { + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + pr_err("Get ATOP_CHIP_ID fail, check = %d\n", check); + return -1; + } + + /* enable TOPDIG CK */ + check = consys_spi_write_nolock(subsystem, ATOP_TOP_CLK_EN, 0xFFFFFFFF); + + /* Disable XO_OUT_B */ + check = consys_spi_read_nolock(subsystem, ATOP_7975_CO_CLK, &value); + check = consys_spi_write_nolock(subsystem, ATOP_7975_CO_CLK, value | 0x02); + + /* Thermal Cal (TOP) */ + _connsys_a_die_thermal_cal(subsystem); + + /* XTAL TRIM */ + _connsys_a_die_xtal_trim_7975(subsystem); + + /* Form Harrier E2 Patch */ + _connsys_a_die_form_patch_7975(subsystem); + + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return 0; +} + +int connsys_a_die_cfg(void) +{ + int ret = 0; + unsigned int i; + + if (one_adie_dbdc) { + /* use adie_idx = 0 */ + if (conn_hw_env[0].valid) { + if (conn_hw_env[0].adie_id == 0x7976) { + ret = _connsys_a_die_cfg_7976(0); + } else if (conn_hw_env[0].adie_id == 0x7975) { + printk(RED("%s: Error(%d): No support!!!"), __func__, __LINE__); + } else { + printk(RED("%s: Error(%d): Unknown Adie type!!!"), __func__, __LINE__); + return -1; + } + } + } else { + for (i = 0; i < AIDE_NUM_MAX; i++) { + if (conn_hw_env[i].valid) { + if (conn_hw_env[i].adie_id == 0x7976) { + ret = _connsys_a_die_cfg_7976(i); + } else if (conn_hw_env[i].adie_id == 0x7975) { + ret = _connsys_a_die_cfg_7975(i); + } else { + printk(RED("%s: Error(%d): Unknown Adie type!!!"), __func__, __LINE__); + return -1; + } + } + } + } + + return ret; +} + +int _connsys_afe_wbg_cal_7976(unsigned char wbg_idx, unsigned char rfspi_idx) +{ + int check; + unsigned long afe_ctl_addr = 0; + unsigned char subsystem = 0; + + if ((wbg_idx == 0) && (rfspi_idx == 0)) { + afe_ctl_addr = REG_CONN_AFE_CTL_ADDR; + subsystem = SYS_SPI_TOP; + } else if ((wbg_idx == 1) && (rfspi_idx == 0)) { + afe_ctl_addr = REG_CONN_AFE_CTL_2ND_ADDR; + subsystem = SYS_SPI_TOP; + } else if ((wbg_idx == 1) && (rfspi_idx == 1)) { + afe_ctl_addr = REG_CONN_AFE_CTL_2ND_ADDR; + subsystem = SYS_SPI_2ND_ADIE_TOP; + } else { + pr_err("No support for this combination (wbg_idx = %d, rfspi_idx = %d)\n", + wbg_idx, rfspi_idx); + return -1; + } + + /* Get semaphore once */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("Require semaphore fail\n"); + return -1; + } + + /* set WF_PAD to HighZ */ + check = consys_spi_write_nolock(subsystem, ATOP_RG_ENCAL_WBTAC_IF_SW, 0x88888005); + + /* AFE WBG CAL SEQ1 (RC calibration) */ + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x1); + udelay(60); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x1); + + /* AFE WBG CAL SEQ2 (TX calibration) */ + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_03, (0x1 << 21)); + udelay(30); + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_03, (0x1 << 20)); + udelay(60); + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x3E0000); + udelay(800); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x3E0000); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_03, 0x300000); + + /* disable WF_PAD to HighZ */ + check = consys_spi_write_nolock(subsystem, ATOP_RG_ENCAL_WBTAC_IF_SW, 0x00000005); + + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return 0; +} + +int _connsys_afe_wbg_cal_7975(unsigned char wbg_idx, unsigned char rfspi_idx) +{ + int check; + unsigned long afe_ctl_addr = 0; + unsigned char subsystem = 0; + + if ((wbg_idx == 0) && (rfspi_idx == 0)) { + afe_ctl_addr = REG_CONN_AFE_CTL_ADDR; + subsystem = SYS_SPI_TOP; + } else if ((wbg_idx == 1) && (rfspi_idx == 0)) { + afe_ctl_addr = REG_CONN_AFE_CTL_2ND_ADDR; + subsystem = SYS_SPI_TOP; + } else if ((wbg_idx == 1) && (rfspi_idx == 1)) { + afe_ctl_addr = REG_CONN_AFE_CTL_2ND_ADDR; + subsystem = SYS_SPI_2ND_ADIE_TOP; + } else { + pr_err("No support for this combination (wbg_idx = %d, rfspi_idx = %d)\n", + wbg_idx, rfspi_idx); + return -1; + } + + /* Get semaphore once */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("Require semaphore fail\n"); + return -1; + } + + /* set WF_PAD to HighZ */ + check = consys_spi_write_nolock(subsystem, ATOP_RG_ENCAL_WBTAC_IF_SW, 0x80000000); + + /* AFE WBG CAL SEQ1 (RC calibration) */ + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x1); + udelay(60); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x1); + + /* AFE WBG CAL SEQ2 (TX calibration) */ + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_03, (0x1 << 21)); + udelay(30); + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_03, (0x1 << 20)); + udelay(60); + CONSYS_SET_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x3E0000); + udelay(800); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_01, 0x3E0000); + CONSYS_CLR_BIT(afe_ctl_addr + RG_DIG_EN_03, 0x300000); + + /* disable WF_PAD to HighZ */ + check = consys_spi_write_nolock(subsystem, ATOP_RG_ENCAL_WBTAC_IF_SW, 0x00000005); + + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + return 0; +} + +int connsys_afe_wbg_cal(void) +{ + int ret; + unsigned int i; + + if (adie_cfg_type == ADIE_TYPE_TWO) { + for (i = 0; i < AIDE_NUM_MAX; i++) { + if (conn_hw_env[i].valid) { + if (conn_hw_env[i].adie_id == 0x7976) { + ret = _connsys_afe_wbg_cal_7976(i, i); + } else if (conn_hw_env[i].adie_id == 0x7975) { + ret = _connsys_afe_wbg_cal_7975(i, i); + } else { + printk(RED("%s: Error(%d): Unknown Adie type!!!"), __func__, __LINE__); + return -1; + } + } + } + } else { + if (one_adie_dbdc) { + /* use adie_idx = 0 */ + if (conn_hw_env[0].valid) { + if (conn_hw_env[0].adie_id == 0x7976) { + ret = _connsys_afe_wbg_cal_7976(0, 0); + ret = _connsys_afe_wbg_cal_7976(1, 0); + } else if (conn_hw_env[0].adie_id == 0x7975) { + printk(RED("%s: Error(%d): No support!!!"), __func__, __LINE__); + } else { + printk(RED("%s: Error(%d): Unknown Adie type!!!"), __func__, __LINE__); + return -1; + } + } + } else { + /* use adie_idx = 1 */ + if (conn_hw_env[1].valid) { + if (conn_hw_env[1].adie_id == 0x7976) { + ret = _connsys_afe_wbg_cal_7976(1, 1); + } else if (conn_hw_env[1].adie_id == 0x7975) { + ret = _connsys_afe_wbg_cal_7975(1, 1); + } else { + printk(RED("%s: Error(%d): Unknown Adie type!!!"), __func__, __LINE__); + return -1; + } + } + } + } + + return ret; +} + +int _connsys_subsys_pll_initial(unsigned char wbg_idx) +{ + unsigned long afe_ctl_addr = 0; + + if (wbg_idx == 0) { + afe_ctl_addr = REG_CONN_AFE_CTL_ADDR; + } else if (wbg_idx == 1) { + afe_ctl_addr = REG_CONN_AFE_CTL_2ND_ADDR; + } else { + pr_err("Not support for this wbg index (wbg_idx=%d)\n", wbg_idx); + return -1; + } + + /* SWITCH(xtal_freq) + CASE SYS_XTAL_40000K + */ + /* set BPLL stable time = 30us (value = 30 * 1000 *1.01 / 25ns) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_PLL_STB_TIME, (0x4BC << 16), 30, 16); + /* set WPLL stable time = 50us (value = 50 * 1000 *1.01 / 25ns) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_PLL_STB_TIME, 0x7E4, 14, 0); + /* BT pll_en will turn on BPLL only (may change in different XTAL option) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_DIG_EN_02, (0x1 << 6), 7, 6); + /* WF pll_en will turn on WPLL only (may change in different XTAL option) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_DIG_EN_02, 0x2, 1, 0); + /* MCU pll_en will turn on BPLL (may change in different XTAL option) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_DIG_EN_02, (0x1 << 2), 3, 2); + /* MCU pll_en will turn on BPLL + WPLL (may change in different XTAL option) */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_DIG_EN_02, (0x2 << 16), 17, 16); + /* CONN_INFRA CLKGEN WPLL AND BPLL REQUEST */ + CONSYS_REG_WRITE_RANGE(afe_ctl_addr + RG_DIG_TOP_01, (0x9 << 15), 18, 15); + + return 0; +} + +int connsys_subsys_pll_initial(void) +{ + int ret; + + ret = _connsys_subsys_pll_initial(0); + ret = _connsys_subsys_pll_initial(1); + + return ret; +} + +int connsys_osc_legacy_mode(void) +{ + /* disable conn_top rc osc_ctrl_top */ + CONSYS_CLR_BIT(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_CFG_RC_CTL_0, 0x80); + CONSYS_REG_WRITE_RANGE(REG_CONN_INFRA_CFG_ADDR + OSC_CTL_0, 0x80706, 23, 0); + + return 0; +} + +int connsys_top_pwr_ctrl(void) +{ + /* prevent subsys from power on/of in a short time interval */ + CONSYS_CLR_BIT_WITH_KEY(REG_CONN_INFRA_RGU_ADDR + BGFYS_ON_TOP_PWR_CTL, 0x40, 0x42540000); + CONSYS_CLR_BIT_WITH_KEY(REG_CONN_INFRA_RGU_ADDR + WFSYS_ON_TOP_PWR_CTL, 0x40, 0x57460000); + + return 0; +} + +int connsys_conn_infra_bus_timeout(void) +{ + /* set conn_infra_off bus timeout */ + CONSYS_REG_WRITE_RANGE(REG_CONN_INFRA_BUS_CR_ADDR + CONN_INFRA_BUS_OFF_TIMEOUT_CTRL, (0x2 << 7), 14, 7); + /* enable conn_infra off bus timeout feature */ + CONSYS_REG_WRITE_RANGE(REG_CONN_INFRA_BUS_CR_ADDR + CONN_INFRA_BUS_OFF_TIMEOUT_CTRL, 0xF, 3, 0); + + /* set conn_infra_on bus timeout */ + CONSYS_REG_WRITE_RANGE(REG_CONN_INFRA_BUS_CR_ADDR + CONN_INFRA_BUS_ON_TIMEOUT_CTRL, (0xC << 7), 14, 7); + /* enable conn_infra_on bus timeout feature */ + CONSYS_REG_WRITE_RANGE(REG_CONN_INFRA_BUS_CR_ADDR + CONN_INFRA_BUS_ON_TIMEOUT_CTRL, 0xF, 3, 0); + + return 0; +} + +int connsys_clkgen_wpll_hw_ctrl(void) +{ + /* set hclk_div_1 with wpll div sel */ + CONSYS_REG_WRITE_MASK(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS_WPLL_DIV_1, 0x4, 0xFC); + + /* set hclk_div_2 with wpll div sel */ + CONSYS_REG_WRITE_MASK(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS_WPLL_DIV_2, 0x4, 0xFC); + +#ifndef CONFIG_FPGA_EARLY_PORTING + /* enable conn_infra bus wpll div_1 */ + CONSYS_SET_BIT(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS_WPLL_DIV_1, 0x1); + + /* enable conn_infra bus wpll div_2 */ + CONSYS_SET_BIT(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS_WPLL_DIV_2, 0x1); +#endif + +#ifndef CONFIG_FPGA_EARLY_PORTING + /* set rfspi wpll div sel + enable rfspis wpll div + */ + CONSYS_REG_WRITE_MASK(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_RFSPI_WPLL_DIV, 0x21, 0xFD); +#else + /* set rfspi wpll div sel */ + CONSYS_REG_WRITE_MASK(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_RFSPI_WPLL_DIV, 0x20, 0xFC); +#endif + + /* disable conn_infra bus clock sw control ==> conn_infra bus clock hw control */ + CONSYS_CLR_BIT(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS, 0x800000); + + /* Conn_infra HW_CONTROL => conn_infra enter dsleep mode */ + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_CFG_PWRCTRL0, 0x1); + + return 0; +} + +int consys_conninfra_top_wakeup(void) +{ + /* wake up conn_infra */ + CONSYS_SET_BIT(REG_CONN_HOST_CSR_TOP_ADDR + CONN_INFRA_WAKEPU_TOP, 0x1); + + /* Wait 900us (apply this for CONNSYS XO clock ready) */ + udelay(900); + + /* Check CONNSYS version ID + * (polling "10 times" for specific project code and each polling interval is "1ms") + */ + if (consys_polling_chipid() != 0) { + pr_err("Polling chip id fail\n"); + return -1; + } + + return 0; +} + +int consys_conninfra_top_sleep(void) +{ + /* release conn_infra force on */ + CONSYS_CLR_BIT(REG_CONN_HOST_CSR_TOP_ADDR + CONN_INFRA_WAKEPU_TOP, 0x1); + + return 0; +} + +int _consys_adie_top_ck_en_on_off_ctrl(unsigned char rfspi_idx, enum consys_drv_type type, unsigned char on) +{ + int check = 0; + unsigned long slp_ctl_addr = 0; + + if (rfspi_idx == 1) + slp_ctl_addr = REG_INST2_CONN_WT_SLP_CTL_REG_ADDR; + else + slp_ctl_addr = REG_CONN_WT_SLP_CTL_REG_ADDR; + + if (type == CONNDRV_TYPE_CONNINFRA) { + if (on) + CONSYS_SET_BIT(slp_ctl_addr + WB_SLP_TOP_CK_0, 0x1); + else + CONSYS_CLR_BIT(slp_ctl_addr + WB_SLP_TOP_CK_0, 0x1); + CONSYS_REG_BIT_POLLING(slp_ctl_addr + WB_SLP_TOP_CK_0, 1, 0, 100, 500, check); + if (check == -1) + pr_err("[type=%d][on=%d] op fail\n", type, on); + } else if (type == CONNDRV_TYPE_WIFI) { + if (on) + CONSYS_SET_BIT(slp_ctl_addr + WB_SLP_TOP_CK_1, 0x1); + else + CONSYS_CLR_BIT(slp_ctl_addr + WB_SLP_TOP_CK_1, 0x1); + CONSYS_REG_BIT_POLLING(slp_ctl_addr + WB_SLP_TOP_CK_1, 1, 0, 100, 500, check); + if (check == -1) + pr_err("[type=%d][on=%d] op fail\n", type, on); + } else { + pr_err("Not support for this consys drv type = %d\n", type); + return -1; + } + + return 0; +} + +int consys_adie_top_ck_en_on_off_ctrl(enum consys_drv_type type, unsigned char on) +{ + int ret; + + if (consys_sema_acquire_timeout(CONN_SEMA_CONN_INFRA_COMMON_SYSRAM_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("[type=%d] acquire semaphore (%d) timeout\n", + type, CONN_SEMA_CONN_INFRA_COMMON_SYSRAM_INDEX); + return -1; + } + + if (adie_cfg_type == ADIE_TYPE_TWO) { + ret = _consys_adie_top_ck_en_on_off_ctrl(0, type, on); + ret = _consys_adie_top_ck_en_on_off_ctrl(1, type, on); + } else { + if (one_adie_dbdc) { + ret = _consys_adie_top_ck_en_on_off_ctrl(0, type, on); + } else { + ret = _consys_adie_top_ck_en_on_off_ctrl(1, type, on); + } + } + + consys_sema_release(CONN_SEMA_CONN_INFRA_COMMON_SYSRAM_INDEX); + + return ret; +} + +bool _is_wmcpu_run_allow(void) +{ + if (EEPROM_content_valid) { + if (one_adie_dbdc) { + if ((band0_pa_type == iPAiLNA) || + (band0_pa_type == iPAeLNA) || + (band1_pa_type == iPAiLNA) || + (band1_pa_type == iPAeLNA)) { + if ((conn_hw_env[0].valid && + (conn_hw_env[0].adie_id == 0x7976) && + (conn_hw_env[0].adie_hw_version == 0x8A20))) { + printk(RED("Wrong EEPROM PA type for this sku!")); + return false; + } + } + } else { + if (adie_cfg_type == ADIE_TYPE_TWO) { + if ((band0_pa_type == iPAiLNA) || + (band0_pa_type == iPAeLNA) || + (band1_pa_type == iPAiLNA) || + (band1_pa_type == iPAeLNA)) { + if ((conn_hw_env[0].valid && (conn_hw_env[0].adie_id == 0x7976)) && + (conn_hw_env[1].valid && (conn_hw_env[1].adie_id == 0x7976))) { + printk(RED("Wrong EEPROM PA type for this sku!")); + return false; + } + } + } + } + } + + return true; +} + +int consys_conninfra_wf_wakeup(void) +{ + /* wake up conn_infra */ + CONSYS_SET_BIT(REG_CONN_HOST_CSR_TOP_ADDR + CONN_INFRA_WAKEPU_WF, 0x1); + + /* Wait 900us (apply this for CONNSYS XO clock ready) */ + udelay(900); + + /* Check CONNSYS version ID + * (polling "10 times" for specific project code and each polling interval is "1ms") + */ + if (consys_polling_chipid() != 0) { + pr_err("Polling chip id fail\n"); + return -1; + } + + return 0; +} + +int consys_conninfra_wf_sleep(void) +{ + CONSYS_CLR_BIT(REG_CONN_HOST_CSR_TOP_ADDR + CONN_INFRA_WAKEPU_WF, 0x1); + + return 0; +} + +int consys_conn_wmcpu_sw_reset(bool bassert) +{ + if (bassert) { + CONSYS_CLR_BIT(REG_CONN_INFRA_RGU_ADDR + WFSYS_CPU_SW_RST_B, 0x1); + } else { + if (_is_wmcpu_run_allow()) + CONSYS_SET_BIT(REG_CONN_INFRA_RGU_ADDR + WFSYS_CPU_SW_RST_B, 0x1); + } + + return 0; +} + +int consys_wf_bus_slp_prot_ctrl(bool enable) +{ + /* Turn on/off "conn_infra to wfsys"/wfsys to conn_infra/wfdma2conn" bus sleep protect */ + + if (enable) + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_CTRL, 0x1); + else + CONSYS_CLR_BIT(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_CTRL, 0x1); + + return 0; +} + +int consys_wfsys_top_on_ctrl(bool enable) +{ + int check = 0; + + if (enable) { + /* turn on wfsys_top_on */ + CONSYS_SET_BIT(REG_CONN_INFRA_RGU_ADDR + WFSYS_ON_TOP_PWR_CTL, 0x57460080); + + /* polling wfsys_rgu_off_hreset_rst_b */ + CONSYS_REG_BIT_POLLING(REG_CONN_HOST_CSR_TOP_ADDR + DBG_DUMMY_3, 30, 1, 100, 500, check); + if (check == -1) + pr_err("[%d] polling wfsys_rgu_off_hreset_rst_b fail\n", enable); + } else { + /* turn off wfsys_top_on */ + CONSYS_CLR_BIT_WITH_KEY(REG_CONN_INFRA_RGU_ADDR + WFSYS_ON_TOP_PWR_CTL, 0x80, 0x57460000); + + /* polling wfsys_rgu_off_hreset_rst_b */ + CONSYS_REG_BIT_POLLING(REG_CONN_HOST_CSR_TOP_ADDR + DBG_DUMMY_3, 30, 0, 100, 500, check); + if (check == -1) + pr_err("[%d] polling wfsys_rgu_off_hreset_rst_b fail\n", enable); + } + + return 0; +} + +int consys_wfsys_bus_slp_prot_check(bool enable) +{ + int check = 0; + + if (enable) { + /* check "conn_infra to wfsys"/wfsys to conn_infra" bus sleep protect turn off */ + CONSYS_REG_BIT_POLLING(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_STATUS, 29, 0, 100, 500, check); + if (check == -1) + pr_err("[bit %d] check conn_infra to wfsys or wfsys to conn_infra bus sleep protect turn off fail\n", 29); + + CONSYS_REG_BIT_POLLING(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_STATUS, 31, 0, 100, 500, check); + if (check == -1) + pr_err("[bit %d] check conn_infra to wfsys or wfsys to conn_infra bus sleep protect turn off fail\n", 31); + + /* check WFDMA2CONN AXI TX bus sleep protect turn off */ + CONSYS_REG_BIT_POLLING(REG_WF_TOP_SLPPROT_ON_ADDR + WF_TOP_SLPPROT_ON_STATUS_READ, 23, 0, 100, 500, check); + if (check == -1) + pr_err("check WFDMA2CONN AXI TX bus sleep protect turn off fail\n"); + + /* check WFDMA2CONN AXI RX bus sleep protect turn off */ + CONSYS_REG_BIT_POLLING(REG_WF_TOP_SLPPROT_ON_ADDR + WF_TOP_SLPPROT_ON_STATUS_READ, 21, 0, 100, 500, check); + if (check == -1) + pr_err("check WFDMA2CONN AXI RX bus sleep protect turn off fail\n"); + + /* check WFSYS version ID */ + CONSYS_REG_POLLING_LARGER_OR_EQUAL(REG_WF_TOP_CFG_ADDR + WF_TOP_CFG_IP_VERSION, 0xFFFFFFFF, 0, 0x02060000, 10, 500, check); + if (check == -1) + pr_err("check WFSYS version ID fail\n"); + } else { + /* check WFDMA2CONN AXI RX bus sleep protect turn on */ + CONSYS_REG_BIT_POLLING(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_STATUS, 25, 1, 100, 500, check); + if (check == -1) + pr_err("check WFDMA2CONN AXI RX bus sleep protect turn on fail\n"); + + /* check "conn_infra to wfsys"/wfsys to conn_infra" bus sleep protect turn on */ + CONSYS_REG_BIT_POLLING(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_STATUS, 29, 1, 100, 500, check); + if (check == -1) + pr_err("[bit %d] check conn_infra to wfsys or wfsys to conn_infra bus sleep protect turn on fail\n", 29); + + CONSYS_REG_BIT_POLLING(REG_CONN_INFRA_CFG_ADDR + CONN_INFRA_WF_SLP_STATUS, 31, 1, 100, 500, check); + if (check == -1) + pr_err("[bit %d] check conn_infra to wfsys or wfsys to conn_infra bus sleep protect turn on fail\n", 31); + } + + return 0; +} + +int consys_wfsys_bus_timeout_ctrl(void) +{ + /* set wfsys bus timeout value (ahb apb timeout) */ + CONSYS_REG_WRITE_MASK(REG_WF_MCU_CONFIG_LS_ADDR + BUSHANGCR, 0x1, 0xFF); + + /* enable wfsys bus timeout (ahb apb timeout) */ + CONSYS_SET_BIT(REG_WF_MCU_CONFIG_LS_ADDR + BUSHANGCR, 0x90000000); + + /* set conn2wf remapping window to wf debug_ctrl_ao CR */ + CONSYS_REG_WRITE(REG_WF_MCU_BUS_CR_ADDR + AP2WF_REMAP_1, 0x810F0000); + + /* set wfsys bus timeout value (debug ctrl ao) */ + CONSYS_REG_WRITE_MASK(REG_WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_ADDR + WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_WFMCU_PWA_CTRL0, + 0x03AA0000, 0xFFFF0000); + + /* enable wfsys bus timeout (debug ctrl ao) */ + CONSYS_SET_BIT(REG_WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_ADDR + WF_MCUSYS_INFRA_BUS_FULL_U_DEBUG_CTRL_AO_WFMCU_PWA_CTRL0, 0xC); + + return 0; +} + +int consys_wmcpu_idle_loop_check(void) +{ + int check = 0; + + /* check CONNSYS power-on completion */ + CONSYS_REG_POLLING_EQUAL(REG_WF_TOP_CFG_ON_ADDR + ROMCODE_INDEX, 0xFFFFFFFF, 0, 0x1D1E, 5000, 1000, check); + if (check == -1) + pr_err("check CONNSYS power-on completion fail\n"); + + return 0; +} + +int _connsys_a_die_chip_id_confirm(unsigned char adie_idx) +{ + int check; + unsigned int adie_chip_id = 0x0; + unsigned char subsystem = 0; + + if (adie_idx == 1) + subsystem = SYS_SPI_2ND_ADIE_TOP; + else + subsystem = SYS_SPI_TOP; + + /* release D Die to A Die Digital reset_b if need */ + if (adie_idx == 1) { + if (CONSYS_REG_READ_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x4) == 0) + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x4); + } else { + if (CONSYS_REG_READ_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x1) == 0) + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + ADIE_CTL, 0x1); + } + + /* Get semaphore once */ + if (consys_sema_acquire_timeout(CONN_SEMA_RFSPI_INDEX, CONN_SEMA_TIMEOUT) == CONN_SEMA_GET_FAIL) { + pr_err("Require semaphore fail\n"); + return -1; + } + + /* read a-die ID */ + check = consys_spi_read_nolock(subsystem, ATOP_CHIP_ID, &adie_chip_id); + if (check) { + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + pr_err("adie_idx[%d]: Get ATOP_CHIP_ID fail, check = %d\n", adie_idx, check); + return -1; + } + + /* Release semaphore */ + consys_sema_release(CONN_SEMA_RFSPI_INDEX); + + if (adie_idx < AIDE_NUM_MAX && (adie_chip_id & 0xFFFF0000) != 0) { + conn_hw_env[adie_idx].valid = true; + conn_hw_env[adie_idx].adie_hw_version = (adie_chip_id & 0xFFFF); + conn_hw_env[adie_idx].adie_id = ((adie_chip_id & 0xFFFF0000) >> 16); + conn_hw_env[adie_idx].is_rc_mode = 0; + + pr_info("adie_idx[%d]: A-die CHIP ID = 0x%x, HW Version = 0x%x\n", + adie_idx, conn_hw_env[adie_idx].adie_id, conn_hw_env[adie_idx].adie_hw_version); + } + + return 0; +} + +int consys_plt_adie_type_check(void) +{ + int ret = 0; + + memset(&conn_hw_env, 0, sizeof(conn_hw_env)); + + if (adie_cfg_type == ADIE_TYPE_TWO) { + ret = _connsys_a_die_chip_id_confirm(0); + ret = _connsys_a_die_chip_id_confirm(1); + if (!(conn_hw_env[0].valid && conn_hw_env[1].valid)){ + adie_cfg_type = ADIE_TYPE_ONE; + printk(RED("%s: Change adie type to one adie"), __func__); + } + } else { + if (one_adie_dbdc) + ret = _connsys_a_die_chip_id_confirm(0); + else + ret = _connsys_a_die_chip_id_confirm(1); + } + + return ret; +} + +int consys_plt_adie_type_cfg(void) +{ + /* + a. Check if One Adie DBDC mode from GPIO8 (0x11D1_021C[2]) + b. To read from falsh EEPROM to decide stream number for several skus + c. + 1. If Strap_GPIO8 == 0 && Read EEPROM Stream Num. + case 1: 2G: 0T0R => One_Adie_SB_AX7800 + then + case 1: A-die is 7976 => + TOP_MISC_CR (0x11D1_021C[31:28]) = 0xA && 0x18050000 = 0xA + case 2: A-die is 7975 => + TOP_MISC_CR (0x11D1_021C[31:28]) = 0x8 && 0x18050000 = 0x8 + 2. If Strap_GPIO8 == 0 && Read EEPROM Stream Num. + case 1: 2G: 2T4R => Two_Adie_SB_AX5400 + case 2: 2G: 4T4R => Two_Adie_SB_AX6000 + then + case 1: A-die is 7976 => + TOP_MISC_CR (0x11D1_021C[31:28]) = 0xF && 0x18050000 = 0xF + case 2: A-die is 7975 => + TOP_MISC_CR (0x11D1_021C[31:28]) = 0xD && 0x18050000 = 0xD + 3. If Strap_GPIO8 == 1 && Read EEPROM Stream Num. + case 1: 2G: 2T2R => One_Adie_DB + then TOP_MISC_CR (0x11D1_021C[31:28]) = 0x7 && 0x18050000 = 0x7 + */ + + if (one_adie_dbdc) { + if (adie_cfg_type == ADIE_TYPE_ONE) { + if ((conn_hw_env[0].valid && (conn_hw_env[0].adie_id == 0x7976))) { + CONSYS_REG_WRITE_MASK(REG_TOP_MISC_ADDR + TOP_MISC_RSRV_ALL1_3, 0x70000000, 0xF0000000); + CONSYS_REG_WRITE(REG_CONN_INFRA_SYSRAM_ADDR + SYSRAM_BASE_ADDR, 0x7); + } else { + printk(RED("%s: Error(%d): Unknown sku type!!!"), __func__, __LINE__); + } + } + } else { + if (adie_cfg_type == ADIE_TYPE_TWO) { + if ((conn_hw_env[0].valid && (conn_hw_env[0].adie_id == 0x7976)) && + (conn_hw_env[1].valid && (conn_hw_env[1].adie_id == 0x7976))) { + CONSYS_REG_WRITE_MASK(REG_TOP_MISC_ADDR + TOP_MISC_RSRV_ALL1_3, 0xF0000000, 0xF0000000); + CONSYS_REG_WRITE(REG_CONN_INFRA_SYSRAM_ADDR + SYSRAM_BASE_ADDR, 0xF); + } else if ((conn_hw_env[0].valid && (conn_hw_env[0].adie_id == 0x7975)) && + (conn_hw_env[1].valid && (conn_hw_env[1].adie_id == 0x7975))) { + CONSYS_REG_WRITE_MASK(REG_TOP_MISC_ADDR + TOP_MISC_RSRV_ALL1_3, 0xD0000000, 0xF0000000); + CONSYS_REG_WRITE(REG_CONN_INFRA_SYSRAM_ADDR + SYSRAM_BASE_ADDR, 0xD); + } else { + printk(RED("%s: Error(%d): Unknown sku type!!!"), __func__, __LINE__); + } + } else { + if ((conn_hw_env[0].valid && (conn_hw_env[0].adie_id == 0x7976)) || + (conn_hw_env[1].valid && (conn_hw_env[1].adie_id == 0x7976))) { + CONSYS_REG_WRITE_MASK(REG_TOP_MISC_ADDR + TOP_MISC_RSRV_ALL1_3, 0xA0000000, 0xF0000000); + CONSYS_REG_WRITE(REG_CONN_INFRA_SYSRAM_ADDR + SYSRAM_BASE_ADDR, 0xA); + } else if ((conn_hw_env[0].valid && (conn_hw_env[0].adie_id == 0x7975)) || + (conn_hw_env[1].valid && (conn_hw_env[1].adie_id == 0x7975))) { + CONSYS_REG_WRITE_MASK(REG_TOP_MISC_ADDR + TOP_MISC_RSRV_ALL1_3, 0x80000000, 0xF0000000); + CONSYS_REG_WRITE(REG_CONN_INFRA_SYSRAM_ADDR + SYSRAM_BASE_ADDR, 0x8); + } else { + printk(RED("%s: Error(%d): Unknown sku type!!!"), __func__, __LINE__); + } + } + } + + if (_consys_check_adie_cfg() == 0) + _consys_check_sku_cfg(); + + return 0; +} + +int consys_wpll_ctrl(bool enable) +{ + if (enable) { + /* turn back wpll setting in conn_afe_ctl by setting wpll initial control to 2'b10 */ + CONSYS_REG_WRITE_MASK(REG_CONN_AFE_CTL_ADDR + RG_DIG_EN_02, 0x20002, 0x30003); + } else { + /* Don't need below code check anymore due to new design */ +#if 0 + int check = 0; + /* trun off wpll enable in conn_afe_ctl by setting wpll initial control to 2'b00 */ + CONSYS_REG_WRITE_MASK(REG_CONN_AFE_CTL_ADDR + RG_DIG_EN_02, 0x0, 0x30003); + + /* polling conn_infra bus to non-wpll case */ + CONSYS_REG_POLLING_EQUAL(REG_CONN_INFRA_CLKGEN_ON_TOP_ADDR + CKGEN_BUS, 0x7800, 11, 0x0, 5000, 1000, check); + if (check == -1) + pr_err("polling conn_infra bus to non-wpll case fail\n"); +#endif + } + + return 0; +} + +int consys_conninfra_wf_req_clr(void) +{ + /* clear wf_emi_req */ + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + EMI_CTL_WF, 0x1); + CONSYS_CLR_BIT(REG_CONN_INFRA_CFG_ADDR + EMI_CTL_WF, 0x1); + + /* clear wf_infra_req */ + CONSYS_SET_BIT(REG_CONN_INFRA_CFG_ADDR + EMI_CTL_WF, 0x20); + CONSYS_CLR_BIT(REG_CONN_INFRA_CFG_ADDR + EMI_CTL_WF, 0x20); + + return 0; +} + diff --git a/package/mtk/drivers/conninfra/src/platform/pmic_mng.c b/package/mtk/drivers/conninfra/src/platform/pmic_mng.c new file mode 100644 index 0000000000..0e8d034ec6 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/platform/pmic_mng.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include "consys_hw.h" +#include "pmic_mng.h" +#include "osal.h" +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +const struct consys_platform_pmic_ops* consys_platform_pmic_ops = NULL; + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +int pmic_mng_init( + struct platform_device *pdev, + struct conninfra_dev_cb* dev_cb, + const struct conninfra_plat_data* plat_data) +{ + if (consys_platform_pmic_ops == NULL) { + consys_platform_pmic_ops = (const struct consys_platform_pmic_ops*)plat_data->platform_pmic_ops; + } + + if (consys_platform_pmic_ops && consys_platform_pmic_ops->consys_pmic_get_from_dts) + consys_platform_pmic_ops->consys_pmic_get_from_dts(pdev, dev_cb); + + return 0; +} + +int pmic_mng_deinit(void) +{ + return 0; +} + +int pmic_mng_common_power_ctrl(unsigned int enable) +{ + int ret = 0; + + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_common_power_ctrl) + ret = consys_platform_pmic_ops->consys_pmic_common_power_ctrl(enable); + + return ret; +} + +int pmic_mng_wifi_power_ctrl(unsigned int enable) +{ + int ret = 0; + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_wifi_power_ctrl) + ret = consys_platform_pmic_ops->consys_pmic_wifi_power_ctrl(enable); + return ret; + +} + +int pmic_mng_bt_power_ctrl(unsigned int enable) +{ + int ret = 0; + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_bt_power_ctrl) + ret = consys_platform_pmic_ops->consys_pmic_bt_power_ctrl(enable); + return ret; +} + +int pmic_mng_gps_power_ctrl(unsigned int enable) +{ + int ret = 0; + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_gps_power_ctrl) + ret = consys_platform_pmic_ops->consys_pmic_gps_power_ctrl(enable); + return ret; +} + +int pmic_mng_fm_power_ctrl(unsigned int enable) +{ + int ret = 0; + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_fm_power_ctrl) + ret = consys_platform_pmic_ops->consys_pmic_fm_power_ctrl(enable); + return ret; +} + + +int pmic_mng_event_cb(unsigned int id, unsigned int event) +{ + if (consys_platform_pmic_ops && + consys_platform_pmic_ops->consys_pmic_event_notifier) + consys_platform_pmic_ops->consys_pmic_event_notifier(id, event); + return 0; +} diff --git a/package/mtk/drivers/conninfra/src/src/conninfra.c b/package/mtk/drivers/conninfra/src/src/conninfra.c new file mode 100644 index 0000000000..4a48679f38 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/src/conninfra.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#define pr_fmt(fmt) KBUILD_MODNAME "@(%s:%d) " fmt, __func__, __LINE__ + +#include +#include +#include +#include +#include +#include +#include +#include "conninfra.h" +#include "emi_mng.h" +#include "conninfra_core.h" +#include "consys_hw.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ + +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +#define CONNINFRA_RST_RATE_LIMIT 0 + +#if CONNINFRA_RST_RATE_LIMIT +DEFINE_RATELIMIT_STATE(g_rs, HZ, 1); + +#define DUMP_LOG() if (__ratelimit(&g_rs)) \ + pr_info("rst is ongoing\n") + +#else +#define DUMP_LOG() +#endif + +struct conninfra_rst_data { + enum consys_drv_type drv; + char *reason; +}; + +struct conninfra_rst_data rst_data; + +void conninfra_get_emi_phy_addr(enum connsys_emi_type type, phys_addr_t* base, unsigned int *size) +{ + struct consys_emi_addr_info* addr_info = emi_mng_get_phy_addr(); + + switch (type) { + case CONNSYS_EMI_FW: + if (base) + *base = addr_info->emi_ap_phy_base; + + if (size) + *size = addr_info->fw_emi_size; + break; + + default: + pr_err("Wrong EMI type: %d\n", type); + if (base) + *base = 0x0; + + if (size) + *size = 0; + break; + } +} +EXPORT_SYMBOL(conninfra_get_emi_phy_addr); + +int conninfra_pwr_on(enum consys_drv_type drv_type) +{ + pr_info("[%s] drv=[%d]\n", __func__, drv_type); + + if (conninfra_core_is_rst_locking()) { + DUMP_LOG(); + return CONNINFRA_ERR_RST_ONGOING; + } + + return conninfra_core_power_on(drv_type); +} +EXPORT_SYMBOL(conninfra_pwr_on); + +int conninfra_pwr_off(enum consys_drv_type drv_type) +{ + if (conninfra_core_is_rst_locking()) { + DUMP_LOG(); + return CONNINFRA_ERR_RST_ONGOING; + } + + return conninfra_core_power_off(drv_type); +} +EXPORT_SYMBOL(conninfra_pwr_off); + +int conninfra_is_bus_hang(void) +{ + if (conninfra_core_is_rst_locking()) { + DUMP_LOG(); + return CONNINFRA_ERR_RST_ONGOING; + } + return conninfra_core_is_bus_hang(); +} +EXPORT_SYMBOL(conninfra_is_bus_hang); + +int conninfra_trigger_whole_chip_rst(enum consys_drv_type who, char *reason) +{ + /* use schedule worker to trigger ??? */ + /* so that function can be returned immediately */ + int r; + + r = conninfra_core_lock_rst(); + if (r >= CHIP_RST_START) { + /* reset is ongoing */ + pr_warn("r=[%d] chip rst is ongoing\n", r); + return 1; + } + pr_info("rst lock [%d] [%d] reason=%s\n", r, who, reason); + + conninfra_core_trg_chip_rst(who, reason); + + return 0; +} +EXPORT_SYMBOL(conninfra_trigger_whole_chip_rst); + +int conninfra_sub_drv_ops_register(enum consys_drv_type type, + struct sub_drv_ops_cb *cb) +{ + /* type validation */ + if (type < 0 || type >= CONNDRV_TYPE_MAX) { + pr_err("incorrect drv type [%d]\n", type); + return -EINVAL; + } + pr_info("----\n"); + conninfra_core_subsys_ops_reg(type, cb); + return 0; +} +EXPORT_SYMBOL(conninfra_sub_drv_ops_register); + +int conninfra_sub_drv_ops_unregister(enum consys_drv_type type) +{ + /* type validation */ + if (type < 0 || type >= CONNDRV_TYPE_MAX) { + pr_err("[%s] incorrect drv type [%d]\n", __func__, type); + return -EINVAL; + } + pr_info("----\n"); + conninfra_core_subsys_ops_unreg(type); + return 0; +} +EXPORT_SYMBOL(conninfra_sub_drv_ops_unregister); + +int conninfra_spi_read(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int *data) +{ + if (conninfra_core_is_rst_locking()) { + DUMP_LOG(); + return CONNINFRA_ERR_RST_ONGOING; + } + if (subsystem >= SYS_SPI_MAX) { + pr_err("wrong subsys %d\n", subsystem); + return -EINVAL; + } + conninfra_core_spi_read(subsystem, addr, data); + return 0; +} +EXPORT_SYMBOL(conninfra_spi_read); + +int conninfra_spi_write(enum sys_spi_subsystem subsystem, unsigned int addr, unsigned int data) +{ + if (conninfra_core_is_rst_locking()) { + DUMP_LOG(); + return CONNINFRA_ERR_RST_ONGOING; + } + + if (subsystem >= SYS_SPI_MAX) { + pr_err("wrong subsys %d\n", subsystem); + return -EINVAL; + } + conninfra_core_spi_write(subsystem, addr, data); + return 0; +} +EXPORT_SYMBOL(conninfra_spi_write); + +int conninfra_adie_top_ck_en_on(enum consys_drv_type type) +{ + if (conninfra_core_is_rst_locking()) { + DUMP_LOG(); + return CONNINFRA_ERR_RST_ONGOING; + } + + return conninfra_core_adie_top_ck_en_on(type); +} +EXPORT_SYMBOL(conninfra_adie_top_ck_en_on); + +int conninfra_adie_top_ck_en_off(enum consys_drv_type type) +{ + if (conninfra_core_is_rst_locking()) { + DUMP_LOG(); + return CONNINFRA_ERR_RST_ONGOING; + } + + return conninfra_core_adie_top_ck_en_off(type); +} +EXPORT_SYMBOL(conninfra_adie_top_ck_en_off); + +int conninfra_spi_clock_switch(enum connsys_spi_speed_type type) +{ + return conninfra_core_spi_clock_switch(type); +} +EXPORT_SYMBOL(conninfra_spi_clock_switch); + +int conninfra_debug_dump(void) +{ + return conninfra_core_debug_dump(); + +} +EXPORT_SYMBOL(conninfra_debug_dump); diff --git a/package/mtk/drivers/conninfra/src/src/conninfra_dev.c b/package/mtk/drivers/conninfra/src/src/conninfra_dev.c new file mode 100644 index 0000000000..0f525dd339 --- /dev/null +++ b/package/mtk/drivers/conninfra/src/src/conninfra_dev.c @@ -0,0 +1,344 @@ +/* + * Copyright (C) 2016 MediaTek Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See http://www.gnu.org/licenses/gpl-2.0.html for more details. + */ +/*! \file +* \brief Declaration of library functions +* +* Any definitions in this file will be shared among GLUE Layer and internal Driver Stack. +*/ + +#include +#include +#include +#include +#include +#include +#include "conninfra.h" +#include "conninfra_core.h" +#include "consys_hw.h" +#include "emi_mng.h" + +/******************************************************************************* +* C O M P I L E R F L A G S +******************************************************************************** +*/ + +/******************************************************************************* +* M A C R O S +******************************************************************************** +*/ + +#define CONNINFRA_DEV_MAJOR 164 +#define CONNINFRA_DEV_NUM 1 +#define CONNINFRA_DRVIER_NAME "conninfra_drv" +#define CONNINFRA_DEVICE_NAME "conninfra_dev" + +#define CONNINFRA_DEV_IOC_MAGIC 0xc2 +#define CONNINFRA_IOCTL_GET_CHIP_ID _IOR(CONNINFRA_DEV_IOC_MAGIC, 0, int) + +#define CONNINFRA_DEV_INIT_TO_MS (2 * 1000) + +/******************************************************************************* +* E X T E R N A L R E F E R E N C E S +******************************************************************************** +*/ + +/******************************************************************************* +* C O N S T A N T S +******************************************************************************** +*/ + +enum conninfra_init_status { + CONNINFRA_INIT_NOT_START, + CONNINFRA_INIT_START, + CONNINFRA_INIT_DONE, +}; +static int g_conninfra_init_status = CONNINFRA_INIT_NOT_START; +static wait_queue_head_t g_conninfra_init_wq; + +/******************************************************************************* +* D A T A T Y P E S +******************************************************************************** +*/ + +/******************************************************************************* +* F U N C T I O N D E C L A R A T I O N S +******************************************************************************** +*/ +static int conninfra_dev_open(struct inode *inode, struct file *file); +static int conninfra_dev_close(struct inode *inode, struct file *file); +static ssize_t conninfra_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos); +static ssize_t conninfra_dev_write(struct file *filp, + const char __user *buf, size_t count, + loff_t *f_pos); +static long conninfra_dev_unlocked_ioctl( + struct file *filp, unsigned int cmd, unsigned long arg); +#ifdef CONFIG_COMPAT +static long conninfra_dev_compat_ioctl( + struct file *filp, unsigned int cmd, unsigned long arg); +#endif /* CONFIG_COMPAT */ + +static int conninfra_dev_suspend_cb(void); +static int conninfra_dev_resume_cb(void); +static int conninfra_dev_pmic_event_cb(unsigned int, unsigned int); +/******************************************************************************* +* P U B L I C D A T A +******************************************************************************** +*/ + +/******************************************************************************* +* P R I V A T E D A T A +******************************************************************************** +*/ + +struct class *pConninfraClass; +struct device *pConninfraDev; +static struct cdev gConninfraCdev; + +const struct file_operations gConninfraDevFops = { + .open = conninfra_dev_open, + .release = conninfra_dev_close, + .read = conninfra_dev_read, + .write = conninfra_dev_write, + .unlocked_ioctl = conninfra_dev_unlocked_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = conninfra_dev_compat_ioctl, +#endif /* CONFIG_COMPAT */ +}; + +static int gConnInfraMajor = CONNINFRA_DEV_MAJOR; + +/* screen on/off notification */ + +static struct conninfra_dev_cb gConninfraDevCb = { + .conninfra_suspend_cb = conninfra_dev_suspend_cb, + .conninfra_resume_cb = conninfra_dev_resume_cb, + .conninfra_pmic_event_notifier = conninfra_dev_pmic_event_cb, +}; + +/******************************************************************************* +* F U N C T I O N S +******************************************************************************** +*/ + +int conninfra_dev_open(struct inode *inode, struct file *file) +{ + static DEFINE_RATELIMIT_STATE(_rs, HZ, 1); + + if (!wait_event_timeout(g_conninfra_init_wq, g_conninfra_init_status == CONNINFRA_INIT_DONE, + msecs_to_jiffies(CONNINFRA_DEV_INIT_TO_MS))) { + if (__ratelimit(&_rs)) { + pr_warn("wait_event_timeout (%d)ms,(%lu)jiffies,return -EIO\n", + CONNINFRA_DEV_INIT_TO_MS, msecs_to_jiffies(CONNINFRA_DEV_INIT_TO_MS)); + } + return -EIO; + } + + pr_info("open major %d minor %d (pid %d)\n", + imajor(inode), iminor(inode), current->pid); + + return 0; +} + +int conninfra_dev_close(struct inode *inode, struct file *file) +{ + pr_info("close major %d minor %d (pid %d)\n", + imajor(inode), iminor(inode), current->pid); + + return 0; +} + +ssize_t conninfra_dev_read(struct file *filp, char __user *buf, + size_t count, loff_t *f_pos) +{ + return 0; +} + +ssize_t conninfra_dev_write(struct file *filp, + const char __user *buf, size_t count, loff_t *f_pos) +{ + return 0; +} + +static long conninfra_dev_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int retval = 0; + + pr_info("[%s] cmd (%d),arg(%ld)\n", __func__, cmd, arg); + switch (cmd) { + case CONNINFRA_IOCTL_GET_CHIP_ID: + retval = consys_hw_chipid_get(); + break; + } + return retval; + +} + +#ifdef CONFIG_COMPAT +static long conninfra_dev_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + long ret; + + pr_info("[%s] cmd (%d)\n", __func__, cmd); + ret = conninfra_dev_unlocked_ioctl(filp, cmd, arg); + return ret; +} +#endif /* CONFIG_COMPAT */ + +static int conninfra_dev_suspend_cb(void) +{ + return 0; +} + +static int conninfra_dev_resume_cb(void) +{ + conninfra_core_dump_power_state(); + return 0; +} + +static int conninfra_dev_pmic_event_cb(unsigned int id, unsigned int event) +{ + conninfra_core_pmic_event_cb(id, event); + + return 0; +} + +/************************************************************************/ + +static int conninfra_dev_init(void) +{ + dev_t devID = MKDEV(gConnInfraMajor, 0); + int cdevErr = -1; + int iret = 0; + + g_conninfra_init_status = CONNINFRA_INIT_START; + init_waitqueue_head((wait_queue_head_t *)&g_conninfra_init_wq); + + iret = register_chrdev_region(devID, CONNINFRA_DEV_NUM, CONNINFRA_DRVIER_NAME); + if (iret) { + pr_err("fail to register chrdev\n"); + g_conninfra_init_status = CONNINFRA_INIT_NOT_START; + return -1; + } + + cdev_init(&gConninfraCdev, &gConninfraDevFops); + gConninfraCdev.owner = THIS_MODULE; + + cdevErr = cdev_add(&gConninfraCdev, devID, CONNINFRA_DEV_NUM); + if (cdevErr) { + pr_err("cdev_add() fails (%d)\n", cdevErr); + goto err1; + } + + pConninfraClass = class_create(THIS_MODULE, CONNINFRA_DEVICE_NAME); + if (IS_ERR(pConninfraClass)) { + pr_err("class create fail, error code(%ld)\n", PTR_ERR(pConninfraClass)); + goto err1; + } + + pConninfraDev = device_create(pConninfraClass, NULL, devID, NULL, CONNINFRA_DEVICE_NAME); + if (IS_ERR(pConninfraDev)) { + pr_err("device create fail, error code(%ld)\n", PTR_ERR(pConninfraDev)); + goto err2; + } + + iret = mtk_conninfra_drv_init(&gConninfraDevCb); + if (iret) { + pr_err("init consys_hw fail, ret = %d\n", iret); + g_conninfra_init_status = CONNINFRA_INIT_NOT_START; + return -2; + } + + iret = conninfra_core_init(); + if (iret) { + pr_err("conninfra init fail\n"); + g_conninfra_init_status = CONNINFRA_INIT_NOT_START; + return -3; + } + + pr_info("ConnInfra Dev: init (%d)\n", iret); + g_conninfra_init_status = CONNINFRA_INIT_DONE; + +#ifdef CONFIG_CONNINFRA_AUTO_UP + iret = conninfra_core_power_on(CONNDRV_TYPE_CONNINFRA); + if (iret) { + pr_err("conninfra auto load power on fail\n"); + return -4; + } +#endif /* CONFIG_CONNINFRA_AUTO_UP */ + + return 0; + +err2: + + pr_err("[conninfra_dev_init] err2\n"); + if (pConninfraClass) { + class_destroy(pConninfraClass); + pConninfraClass = NULL; + } +err1: + pr_err("[conninfra_dev_init] err1\n"); + if (cdevErr == 0) + cdev_del(&gConninfraCdev); + + if (iret == 0) { + unregister_chrdev_region(devID, CONNINFRA_DEV_NUM); + gConnInfraMajor = -1; + } + + g_conninfra_init_status = CONNINFRA_INIT_NOT_START; + return -2; +} + +static void conninfra_dev_deinit(void) +{ + dev_t dev = MKDEV(gConnInfraMajor, 0); + int iret = 0; + +#ifdef CONFIG_CONNINFRA_AUTO_UP + iret = conninfra_core_power_off(CONNDRV_TYPE_CONNINFRA); + if (iret) { + pr_err("conninfra auto load power off fail\n"); + } +#endif /* CONFIG_CONNINFRA_AUTO_UP */ + + g_conninfra_init_status = CONNINFRA_INIT_NOT_START; + + iret = conninfra_core_deinit(); + + iret = mtk_conninfra_drv_deinit(); + + if (pConninfraDev) { + device_destroy(pConninfraClass, dev); + pConninfraDev = NULL; + } + + if (pConninfraClass) { + class_destroy(pConninfraClass); + pConninfraClass = NULL; + } + + cdev_del(&gConninfraCdev); + unregister_chrdev_region(dev, CONNINFRA_DEV_NUM); + + pr_info("ConnInfra: platform init (%d)\n", iret); +} + +module_init(conninfra_dev_init); +module_exit(conninfra_dev_deinit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Willy.Yu @ CTD/SE5/CS5"); + +module_param(gConnInfraMajor, uint, 0644); +