blob: 97c3c84a76084a13b8a97fe6e5bc59cc015ecbd6 [file] [log] [blame]
/*
* NDA AND NEED-TO-KNOW REQUIRED
*
* Copyright © 2013-2018 Synaptics Incorporated. All rights reserved.
*
* This file contains information that is proprietary to Synaptics
* Incorporated ("Synaptics"). The holder of this file shall treat all
* information contained herein as confidential, shall use the
* information only for its intended purpose, and shall not duplicate,
* disclose, or disseminate any of this information in any manner
* unless Synaptics has otherwise provided express, written
* permission.
*
* Use of the materials may require a license of intellectual property
* from a third party or from Synaptics. This file conveys no express
* or implied licenses to any intellectual property rights belonging
* to Synaptics.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND
* SYNAPTICS EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE, AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY
* INTELLECTUAL PROPERTY RIGHTS. IN NO EVENT SHALL SYNAPTICS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR
* CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE USE
* OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED AND
* BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF
* COMPETENT JURISDICTION DOES NOT PERMIT THE DISCLAIMER OF DIRECT
* DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' TOTAL CUMULATIVE LIABILITY
* TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. DOLLARS.
*/
#include <stdint.h>
#include "libfdt.h"
#include "libfdt_mrvl.h"
#include "string.h"
#include "debug.h"
#include "lgpl_printf.h"
#include "pmic_select.h"
/*
* Add or modify node into the provided FDT.
* add ramdisk addr/ramdisk size and modify cmdline to FDT.
* REturn values:
* = 0 -> pretend success
*/
int set_fdt(void *fdt, int total_space,unsigned int initrd_start,unsigned int initrd_size,char * cmdline)
{
int ret;
int offset = 0;
/* let's give it all the room it could need */
ret = fdt_open_into(fdt, fdt, total_space);
if (ret < 0)
return ret;
/* find the offset in FDT */
offset = fdt_path_offset(fdt,"/chosen");
if (offset == -FDT_ERR_NOTFOUND){
offset = fdt_add_subnode(fdt, 0, "/chosen");
if (offset < 0)
return offset;
}
/* modify the bootargs in FDT */
if(cmdline != NULL)
{
ret = fdt_setprop_string(fdt, offset, "bootargs", cmdline);
if(ret)
return ret;
}
if(initrd_size != 0) {
/* add ramdisk addr/ramdisk size to FDT */
ret = fdt_setprop_cell(fdt, offset,"linux,initrd-start",initrd_start);
if(ret)
return ret;
ret = fdt_setprop_cell(fdt, offset,"linux,initrd-end",initrd_start + initrd_size);
if(ret)
return ret;
}
return fdt_pack(fdt);
}
static unsigned int g_fdt = 0;
static int g_total_space = 0;
static int check_fdt_validate(void)
{
if((g_fdt == 0) || (g_total_space <= 0))
return FDT_ERR_NOTFOUND;
return 0;
}
void fdt_set_reserved_mem(void *fdt, unsigned int address, unsigned int size)
{
struct fdt_header * header = (struct fdt_header *)fdt;
unsigned int offset = fdt32_to_cpu(header->off_mem_rsvmap);
struct fdt_reserve_entry * mem_reserve = (struct fdt_reserve_entry *)(((unsigned char *)fdt) + offset);
if(mem_reserve->size != 0) {
mem_reserve->address = cpu_to_fdt64(address);
mem_reserve->size = cpu_to_fdt64(size);
}
}
/* set the address and size of dtb first */
void set_fdt_addr(unsigned int fdt, int total_space)
{
g_fdt = fdt;
g_total_space = total_space;
}
int get_fdt_addr(unsigned int *fdt, int * total_space)
{
if(check_fdt_validate() == 0) {
*fdt = g_fdt;
*total_space = g_total_space;
return 0;
}
return FDT_ERR_NOTFOUND;
}
/* pass system info (rkek_id, chip_ver) to kernel.*/
int fdt_add_system_info(void *fdt,
int total_space,
const char *pnode,
const system_info_t *system_info)
{
int ret;
int offset = 0;
char buf[128] = {0};
ret = fdt_open_into(fdt, fdt, total_space);
if (ret < 0)
return ret;
offset = fdt_path_offset(fdt, pnode);
if (offset == -FDT_ERR_NOTFOUND){
offset = fdt_add_subnode(fdt, 0, pnode);
if (offset < 0)
return offset;
}
sprintf(buf, "%08x\n", system_info->chip_ver);
ret = fdt_setprop(fdt, offset, "system_rev", buf, strlen(buf) + 1);
if(ret)
return ret;
sprintf(buf, "%08x%08x\n", system_info->system_serial_low, system_info->system_serial_high);
ret = fdt_setprop(fdt, offset, "system_serial", buf, strlen(buf) + 1);
if(ret)
return ret;
sprintf(buf, "Revision\t: %08x\nSerial\t\t: %08x%08x\n", system_info->chip_ver, system_info->system_serial_low, system_info->system_serial_high);
ret = fdt_setprop(fdt, offset, "system_info", buf, strlen(buf) + 1);
if(ret)
return ret;
sprintf(buf, "%08x\n", system_info->leakage_current);
ret = fdt_setprop(fdt, offset, "leakage_current", buf, strlen(buf) + 1);
if(ret)
return ret;
sprintf(buf, "%08x\n", system_info->temp_id);
ret = fdt_setprop(fdt, offset, "temp_id", buf, strlen(buf) + 1);
if(ret)
return ret;
sprintf(buf, "%08x\n", system_info->leakage_current_v1);
ret = fdt_setprop(fdt, offset, "leakage_current_v1", buf, strlen(buf) + 1);
if(ret)
return ret;
sprintf(buf, "%08x\n", system_info->temp_id_v1);
ret = fdt_setprop(fdt, offset, "temp_id_v1", buf, strlen(buf) + 1);
if(ret)
return ret;
sprintf(buf, "%08x\n", system_info->leakage_current_v2);
ret = fdt_setprop(fdt, offset, "leakage_current_v2", buf, strlen(buf) + 1);
if(ret)
return ret;
sprintf(buf, "%08x\n", system_info->temp_id_v2);
ret = fdt_setprop(fdt, offset, "temp_id_v2", buf, strlen(buf) + 1);
if(ret)
return ret;
sprintf(buf, "%u\n", system_info->chip_timestamp);
ret = fdt_setprop(fdt, offset, "chip_timestamp", buf, strlen(buf) + 1);
if(ret)
return ret;
sprintf(buf, "%u\n", system_info->pcie_disable);
ret = fdt_setprop(fdt, offset, "pcie_disable", buf, strlen(buf) + 1);
if (ret)
return ret;
sprintf(buf, "%08x\n", system_info->pvcomp_rev);
ret = fdt_setprop(fdt, offset, "pvcomp_rev", buf, strlen(buf) + 1);
if(ret)
return ret;
return fdt_pack(fdt);
}
/* update the i2c slave address of pmic */
int fdt_update_i2c_slave_addr(void *fdt, int total_space, unsigned int masterid, unsigned int slave_addr)
{
int ret;
int offset = 0;
unsigned int reg = 0;
/* let's give it all the room it could need */
ret = fdt_open_into(fdt, fdt, total_space);
if (ret < 0)
return ret;
if(masterid == 0)
offset = fdt_path_offset(fdt, "/soc/apb@e80000/i2c@1400/pg867");
else
offset = fdt_path_offset(fdt, "/soc/apb@e80000/i2c@3400/pg867");
if (offset == -FDT_ERR_NOTFOUND) {
lgpl_printf("didn't find point of i2c\n");
return -1;
}
reg = cpu_to_fdt32(slave_addr);
fdt_setprop(fdt, offset, "reg", &reg, sizeof(unsigned int));
return fdt_pack(fdt);
}
/* pass opp table to kernel */
int fdt_add_opp(void *fdt, int total_space, unsigned int * opp, int count)
{
int ret;
int offset = 0, i = 0;
if(count == 0) {
lgpl_printf("opp table is NULL!!!!\n");
return -1;
}
for(i = 0; i < count; i++) {
opp[i] = cpu_to_fdt32(opp[i]);
}
/* let's give it all the room it could need */
ret = fdt_open_into(fdt, fdt, total_space);
if (ret < 0)
return ret;
offset = fdt_path_offset(fdt, "/cpus/cpu@0");
if (offset == -FDT_ERR_NOTFOUND) {
lgpl_printf("didn't find point of cpus\n");
return -1;
}
fdt_setprop(fdt, offset, "operating-points", opp, sizeof(unsigned int) * count);
return fdt_pack(fdt);
}
static void update_opp(void *buf, int offset, unsigned int vh, unsigned int vl)
{
int node;
const unsigned int *p;
unsigned int v1, v3, vol_h[3], vol_l[3];
/* opp-microvolt = <vh vh vh>; */
vol_h[2] = vol_h[1] = vol_h[0] = cpu_to_fdt32(vh);
/* opp-microvolt = <vl vl vh>; */
vol_l[2] = cpu_to_fdt32(vh);
vol_l[1] = vol_l[0] = cpu_to_fdt32(vl);
for(node = fdt_first_subnode(buf, offset); node >= 0;
node = fdt_next_subnode(buf, node)) {
p = fdt_getprop(buf, node, "opp-microvolt", NULL);
if (!p)
continue;
v1 = fdt32_to_cpu(*p);
p += 2;
v3 = fdt32_to_cpu(*p);
if (v1 < v3)
fdt_setprop(buf, node, "opp-microvolt", vol_l, sizeof(vol_l));
else
fdt_setprop(buf, node, "opp-microvolt", vol_h, sizeof(vol_h));
}
}
void fdt_set_vcpu_opp(void * fdt, unsigned int vh, unsigned int vl)
{
int offset;
unsigned int vcpuh, vcpul, vcoreh, vcorel;
vcpuh = vcoreh = vh;
vcpul = vcorel = vl;
offset = fdt_path_offset(fdt, "/cpus/opp_table0");
if (offset < 0) {
lgpl_printf("didn't find point of /cpus/opp_table0\n");
return;
}
update_opp(fdt, offset, vcpuh, vcpul);
offset = fdt_node_offset_by_compatible(fdt, offset,
"operating-points-v2");
while (offset != -FDT_ERR_NOTFOUND) {
update_opp(fdt, offset, vcoreh, vcorel);
offset = fdt_node_offset_by_compatible(fdt, offset,
"operating-points-v2");
}
}
void fdt_set_vcore_opp(void * fdt, unsigned int vcoreh, unsigned int vcorel)
{
int offset;
offset = fdt_path_offset(fdt, "/soc/vcore_opp_table");
if (offset < 0) {
lgpl_printf("didn't find point of /soc/vcore_opp_table\n");
return;
}
update_opp(fdt, offset, vcoreh, vcorel);
}
int fdt_set_leakage(void *fdt, int total_space, unsigned int leakage_num)
{
int ret;
int offset = 0;
unsigned int leakage = 0x0;
/* let's give it all the room it could need */
ret = fdt_open_into(fdt, fdt, total_space);
if(ret < 0)
return ret;
/* find the offset in FDT*/
offset = fdt_path_offset(fdt, "/soc/cpm");
if(offset == -FDT_ERR_NOTFOUND) {
lgpl_printf("didn't find point of /soc/cpm\n");
return offset;
}
leakage = cpu_to_fdt32(leakage_num);
fdt_setprop(fdt, offset, "leakage", (const void *)(uintptr_t)(&leakage), sizeof(leakage));
return fdt_pack(fdt);
}
int fdt_set_chip_rev(void *fdt, int total_space, unsigned int chip_rev)
{
int ret;
int offset = 0;
unsigned int chip_revision = 0x0;
/* let's give it all the room it could need */
ret = fdt_open_into(fdt, fdt, total_space);
if(ret < 0)
return ret;
/* find the offset in FDT*/
offset = fdt_path_offset(fdt, "/soc/chipid@ea0000");
if(offset == -FDT_ERR_NOTFOUND) {
lgpl_printf("didn't find point of /soc/chipid@ea0000\n");
return offset;
}
chip_revision = cpu_to_fdt32(chip_rev);
fdt_setprop(fdt, offset, "chip-revision", (const void *)(uintptr_t)(&chip_revision), sizeof(chip_revision));
return fdt_pack(fdt);
}
void fdt_select_pmic(void *fdt)
{
int offset = 0;
unsigned int pmic_id = get_pmic_id();
if (SY8824B == pmic_id) {
lgpl_printf("Select PMIC chip sy8824b for Kernel !\n");
/* enable SY8824 */
offset = fdt_node_offset_by_compatible(fdt, -1, "silergy,sy8824");
while(offset > 0) {
lgpl_printf("Update silergy,sy8824!\n");
uint32_t phandle = fdt_get_phandle(fdt, offset);
fdt_setprop_string(fdt, offset, "status", "okay");
if((phandle != (uint32_t)(-1)) && phandle) {
int cpu0_offset = fdt_path_offset(fdt, "/cpus/cpu@0");
lgpl_printf("Update cpu0-supply!\n");
fdt_setprop_u32(fdt, cpu0_offset, "cpu0-supply", phandle);
}
offset = fdt_node_offset_by_compatible(fdt, offset, "silergy,sy8824");
}
}
else {
/* disable SY8824 */
offset = fdt_node_offset_by_compatible(fdt, -1, "silergy,sy8824");
while(offset > 0) {
lgpl_printf("Delete silergy,sy8824 for Kernel !\n");
fdt_del_node(fdt, offset);
offset = fdt_node_offset_by_compatible(fdt, offset, "silergy,sy8824");
}
}
if (SY20276 == pmic_id) {
lgpl_printf("Select PMIC chip sy20276 for Kernel !\n");
/* enable SY20276 */
offset = fdt_node_offset_by_compatible(fdt, -1, "silergy,sy20276");
while(offset > 0) {
lgpl_printf("Update silergy,sy20276!\n");
uint32_t phandle = fdt_get_phandle(fdt, offset);
fdt_setprop_string(fdt, offset, "status", "okay");
if((phandle != (uint32_t)(-1)) && phandle) {
int cpu0_offset = fdt_path_offset(fdt, "/cpus/cpu@0");
lgpl_printf("Update cpu0-supply!\n");
fdt_setprop_u32(fdt, cpu0_offset, "cpu0-supply", phandle);
}
offset = fdt_node_offset_by_compatible(fdt, offset, "silergy,sy20276");
}
}
else {
/* disable SY20276 */
offset = fdt_node_offset_by_compatible(fdt, -1, "silergy,sy20276");
while(offset > 0) {
lgpl_printf("Delete silergy,sy20276 for Kernel !\n");
fdt_del_node(fdt, offset);
offset = fdt_node_offset_by_compatible(fdt, offset, "silergy,sy20276");
}
}
if (SY20278 == pmic_id) {
lgpl_printf("Select PMIC chip sy20278 for Kernel !\n");
/* enable SY20278 */
offset = fdt_node_offset_by_compatible(fdt, -1, "silergy,sy20278");
while(offset > 0) {
lgpl_printf("Update silergy,sy20278!\n");
uint32_t phandle = fdt_get_phandle(fdt, offset);
fdt_setprop_string(fdt, offset, "status", "okay");
if((phandle != (uint32_t)(-1)) && phandle) {
int cpu0_offset = fdt_path_offset(fdt, "/cpus/cpu@0");
lgpl_printf("Update cpu0-supply!\n");
fdt_setprop_u32(fdt, cpu0_offset, "cpu0-supply", phandle);
}
offset = fdt_node_offset_by_compatible(fdt, offset, "silergy,sy20278");
}
}
else {
/* disable SY20278 */
offset = fdt_node_offset_by_compatible(fdt, -1, "silergy,sy20278");
while(offset > 0) {
lgpl_printf("Delete silergy,sy20278 for Kernel !\n");
fdt_del_node(fdt, offset);
offset = fdt_node_offset_by_compatible(fdt, offset, "silergy,sy20278");
}
}
}
void fdt_set_memory(void *fdt, unsigned int memory_size) {
int offset;
unsigned int reg[4];
int memory_offset = 0x01000000;
/* find the offset in FDT */
offset = fdt_path_offset(fdt,"/memory");
if (offset == -FDT_ERR_NOTFOUND){
offset = fdt_add_subnode(fdt, 0, "/memory");
if (offset < 0)
lgpl_printf("Failed to find memory in the fdt !\n");
return;
}
lgpl_printf("set memory 0x%x to fdt !\n", memory_size);
reg[0] = cpu_to_fdt32(0);
reg[1] = cpu_to_fdt32(memory_offset);
reg[2] = cpu_to_fdt32(0);
reg[3] = cpu_to_fdt32(memory_size - memory_offset);
fdt_setprop(fdt, offset, "reg", &reg, sizeof(reg));
}
void fdt_set_ramoops(void *fdt, unsigned int memory_size) {
int offset;
unsigned int reg[4];
unsigned int reserved_size = 0x00100000;
/* find the offset in FDT */
offset = fdt_node_offset_by_compatible(fdt, -1, "ramoops");
if (offset == -FDT_ERR_NOTFOUND){
lgpl_printf("Failed to find ramoops in the fdt !\n");
}
reg[0] = cpu_to_fdt32(0);
reg[1] = cpu_to_fdt32(memory_size - reserved_size);;
reg[2] = cpu_to_fdt32(0);
reg[3] = cpu_to_fdt32(reserved_size);
fdt_setprop(fdt, offset, "reg", &reg, sizeof(reg));
}