/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "pp_debug.h"
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "atom.h"
#include "ppatomctrl.h"
#include "atombios.h"
#include "cgs_common.h"
#define MEM_ID_MASK 0xff000000
#define MEM_ID_SHIFT 24
#define CLOCK_RANGE_MASK 0x00ffffff
#define CLOCK_RANGE_SHIFT 0
#define LOW_NIBBLE_MASK 0xf
#define DATA_EQU_PREV 0
#define DATA_FROM_TABLE 4
union voltage_object_info {
struct _ATOM_VOLTAGE_OBJECT_INFO v1;
struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2;
struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3;
};
static int atomctrl_retrieve_ac_timing(
uint8_t index,
ATOM_INIT_REG_BLOCK *reg_block,
pp_atomctrl_mc_reg_table *table)
{
uint32_t i, j;
uint8_t tmem_id;
ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
((uint8_t *)reg_block + (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block->usRegIndexTblSize));
uint8_t num_ranges = 0;
while (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK &&
num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES) {
tmem_id = (uint8_t)((*(uint32_t *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
if (index == tmem_id) {
table->mc_reg_table_entry[num_ranges].mclk_max =
(uint32_t)((*(uint32_t *)reg_data & CLOCK_RANGE_MASK) >>
CLOCK_RANGE_SHIFT);
for (i = 0, j = 1; i < table->last; i++) {
if ((table->mc_reg_address[i].uc_pre_reg_data &
LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
table->mc_reg_table_entry[num_ranges].mc_data[i] =
(uint32_t)*((uint32_t *)reg_data + j);
j++;
} else if ((table->mc_reg_address[i].uc_pre_reg_data &
LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
if (i)
table->mc_reg_table_entry[num_ranges].mc_data[i] =
table->mc_reg_table_entry[num_ranges].mc_data[i-1];
}
}
num_ranges++;
}
reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
((uint8_t *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)) ;
}
PP_ASSERT_WITH_CODE((*(uint32_t *)reg_data == END_OF_REG_DATA_BLOCK),
"Invalid VramInfo table.", return -1);
table->num_entries = num_ranges;
return 0;
}
/**
* atomctrl_set_mc_reg_address_table - Get memory clock AC timing registers index from VBIOS table
* VBIOS set end of memory clock AC timing registers by ucPreRegDataLength bit6 = 1
* @reg_block: the address ATOM_INIT_REG_BLOCK
* @table: the address of MCRegTable
* Return: 0
*/
static int atomctrl_set_mc_reg_address_table(
ATOM_INIT_REG_BLOCK *reg_block,
pp_atomctrl_mc_reg_table *table)
{
uint8_t i = 0;
uint8_t num_entries = (uint8_t)((le16_to_cpu(reg_block->usRegIndexTblSize))
/ sizeof(ATOM_INIT_REG_INDEX