aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/display/dc/dce
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dce')
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_aux.c647
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_aux.h30
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c123
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h35
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c196
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c129
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h12
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c79
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h8
10 files changed, 476 insertions, 791 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
index aaeb7faac0c4..adbb22224e1a 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
@@ -24,6 +24,7 @@
*/
#include "dm_services.h"
+#include "core_types.h"
#include "dce_aux.h"
#include "dce/dce_11_0_sh_mask.h"
@@ -41,17 +42,17 @@
container_of((ptr), struct aux_engine_dce110, base)
#define FROM_ENGINE(ptr) \
- FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
+ FROM_AUX_ENGINE(container_of((ptr), struct dce_aux, base))
#define FROM_AUX_ENGINE_ENGINE(ptr) \
- container_of((ptr), struct aux_engine, base)
+ container_of((ptr), struct dce_aux, base)
enum {
AUX_INVALID_REPLY_RETRY_COUNTER = 1,
AUX_TIMED_OUT_RETRY_COUNTER = 2,
AUX_DEFER_RETRY_COUNTER = 6
};
static void release_engine(
- struct aux_engine *engine)
+ struct dce_aux *engine)
{
struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
@@ -66,7 +67,7 @@ static void release_engine(
#define DMCU_CAN_ACCESS_AUX 2
static bool is_engine_available(
- struct aux_engine *engine)
+ struct dce_aux *engine)
{
struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
@@ -79,7 +80,7 @@ static bool is_engine_available(
return (field != DMCU_CAN_ACCESS_AUX);
}
static bool acquire_engine(
- struct aux_engine *engine)
+ struct dce_aux *engine)
{
struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
@@ -155,7 +156,7 @@ static bool acquire_engine(
(0xFF & (address))
static void submit_channel_request(
- struct aux_engine *engine,
+ struct dce_aux *engine,
struct aux_request_transaction_data *request)
{
struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
@@ -247,7 +248,7 @@ static void submit_channel_request(
REG_UPDATE(AUX_SW_CONTROL, AUX_SW_GO, 1);
}
-static int read_channel_reply(struct aux_engine *engine, uint32_t size,
+static int read_channel_reply(struct dce_aux *engine, uint32_t size,
uint8_t *buffer, uint8_t *reply_result,
uint32_t *sw_status)
{
@@ -273,7 +274,8 @@ static int read_channel_reply(struct aux_engine *engine, uint32_t size,
REG_GET(AUX_SW_DATA, AUX_SW_DATA, &reply_result_32);
reply_result_32 = reply_result_32 >> 4;
- *reply_result = (uint8_t)reply_result_32;
+ if (reply_result != NULL)
+ *reply_result = (uint8_t)reply_result_32;
if (reply_result_32 == 0) { /* ACK */
uint32_t i = 0;
@@ -299,61 +301,8 @@ static int read_channel_reply(struct aux_engine *engine, uint32_t size,
return 0;
}
-static void process_channel_reply(
- struct aux_engine *engine,
- struct aux_reply_transaction_data *reply)
-{
- int bytes_replied;
- uint8_t reply_result;
- uint32_t sw_status;
-
- bytes_replied = read_channel_reply(engine, reply->length, reply->data,
- &reply_result, &sw_status);
-
- /* in case HPD is LOW, exit AUX transaction */
- if ((sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
- reply->status = AUX_TRANSACTION_REPLY_HPD_DISCON;
- return;
- }
-
- if (bytes_replied < 0) {
- /* Need to handle an error case...
- * Hopefully, upper layer function won't call this function if
- * the number of bytes in the reply was 0, because there was
- * surely an error that was asserted that should have been
- * handled for hot plug case, this could happens
- */
- if (!(sw_status & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK)) {
- reply->status = AUX_TRANSACTION_REPLY_INVALID;
- ASSERT_CRITICAL(false);
- return;
- }
- } else {
-
- switch (reply_result) {
- case 0: /* ACK */
- reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
- break;
- case 1: /* NACK */
- reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
- break;
- case 2: /* DEFER */
- reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
- break;
- case 4: /* AUX ACK / I2C NACK */
- reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
- break;
- case 8: /* AUX ACK / I2C DEFER */
- reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
- break;
- default:
- reply->status = AUX_TRANSACTION_REPLY_INVALID;
- }
- }
-}
-
static enum aux_channel_operation_result get_channel_status(
- struct aux_engine *engine,
+ struct dce_aux *engine,
uint8_t *returned_bytes)
{
struct aux_engine_dce110 *aux110 = FROM_AUX_ENGINE(engine);
@@ -414,469 +363,22 @@ static enum aux_channel_operation_result get_channel_status(
return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
}
}
-static void process_read_reply(
- struct aux_engine *engine,
- struct read_command_context *ctx)
-{
- engine->funcs->process_channel_reply(engine, &ctx->reply);
-
- switch (ctx->reply.status) {
- case AUX_TRANSACTION_REPLY_AUX_ACK:
- ctx->defer_retry_aux = 0;
- if (ctx->returned_byte > ctx->current_read_length) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else if (ctx->returned_byte < ctx->current_read_length) {
- ctx->current_read_length -= ctx->returned_byte;
-
- ctx->offset += ctx->returned_byte;
-
- ++ctx->invalid_reply_retry_aux_on_ack;
-
- if (ctx->invalid_reply_retry_aux_on_ack >
- AUX_INVALID_REPLY_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- }
- } else {
- ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
- ctx->transaction_complete = true;
- ctx->operation_succeeded = true;
- }
- break;
- case AUX_TRANSACTION_REPLY_AUX_NACK:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
- ctx->operation_succeeded = false;
- break;
- case AUX_TRANSACTION_REPLY_AUX_DEFER:
- ++ctx->defer_retry_aux;
-
- if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_I2C_DEFER:
- ctx->defer_retry_aux = 0;
-
- ++ctx->defer_retry_i2c;
-
- if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-static void process_read_request(
- struct aux_engine *engine,
- struct read_command_context *ctx)
-{
- enum aux_channel_operation_result operation_result;
- engine->funcs->submit_channel_request(engine, &ctx->request);
-
- operation_result = engine->funcs->get_channel_status(
- engine, &ctx->returned_byte);
-
- switch (operation_result) {
- case AUX_CHANNEL_OPERATION_SUCCEEDED:
- if (ctx->returned_byte > ctx->current_read_length) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else {
- ctx->timed_out_retry_aux = 0;
- ctx->invalid_reply_retry_aux = 0;
-
- ctx->reply.length = ctx->returned_byte;
- ctx->reply.data = ctx->buffer;
-
- process_read_reply(engine, ctx);
- }
- break;
- case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
- ++ctx->invalid_reply_retry_aux;
-
- if (ctx->invalid_reply_retry_aux >
- AUX_INVALID_REPLY_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else
- udelay(400);
- break;
- case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
- ++ctx->timed_out_retry_aux;
-
- if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- } else {
- /* DP 1.2a, table 2-58:
- * "S3: AUX Request CMD PENDING:
- * retry 3 times, with 400usec wait on each"
- * The HW timeout is set to 550usec,
- * so we should not wait here
- */
- }
- break;
- case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-static bool read_command(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction)
-{
- struct read_command_context ctx;
-
- ctx.buffer = request->payload.data;
- ctx.current_read_length = request->payload.length;
- ctx.offset = 0;
- ctx.timed_out_retry_aux = 0;
- ctx.invalid_reply_retry_aux = 0;
- ctx.defer_retry_aux = 0;
- ctx.defer_retry_i2c = 0;
- ctx.invalid_reply_retry_aux_on_ack = 0;
- ctx.transaction_complete = false;
- ctx.operation_succeeded = true;
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- ctx.request.type = AUX_TRANSACTION_TYPE_DP;
- ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
- ctx.request.address = request->payload.address;
- } else if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
- ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
- ctx.request.action = middle_of_transaction ?
- I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_READ;
- ctx.request.address = request->payload.address >> 1;
- } else {
- /* in DAL2, there was no return in such case */
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- ctx.request.delay = 0;
-
- do {
- memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
-
- ctx.request.data = ctx.buffer + ctx.offset;
- ctx.request.length = ctx.current_read_length;
-
- process_read_request(engine, &ctx);
-
- request->status = ctx.status;
-
- if (ctx.operation_succeeded && !ctx.transaction_complete)
- if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
- msleep(engine->delay);
- } while (ctx.operation_succeeded && !ctx.transaction_complete);
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- DC_LOG_I2C_AUX("READ: addr:0x%x value:0x%x Result:%d",
- request->payload.address,
- request->payload.data[0],
- ctx.operation_succeeded);
- }
-
- return ctx.operation_succeeded;
-}
-
-static void process_write_reply(
- struct aux_engine *engine,
- struct write_command_context *ctx)
-{
- engine->funcs->process_channel_reply(engine, &ctx->reply);
-
- switch (ctx->reply.status) {
- case AUX_TRANSACTION_REPLY_AUX_ACK:
- ctx->operation_succeeded = true;
-
- if (ctx->returned_byte) {
- ctx->request.action = ctx->mot ?
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
-
- ctx->current_write_length = 0;
-
- ++ctx->ack_m_retry;
-
- if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- } else
- udelay(300);
- } else {
- ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
- ctx->defer_retry_aux = 0;
- ctx->ack_m_retry = 0;
- ctx->transaction_complete = true;
- }
- break;
- case AUX_TRANSACTION_REPLY_AUX_NACK:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
- ctx->operation_succeeded = false;
- break;
- case AUX_TRANSACTION_REPLY_AUX_DEFER:
- ++ctx->defer_retry_aux;
-
- if (ctx->defer_retry_aux > ctx->max_defer_retry) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_I2C_DEFER:
- ctx->defer_retry_aux = 0;
- ctx->current_write_length = 0;
-
- ctx->request.action = ctx->mot ?
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
-
- ++ctx->defer_retry_i2c;
-
- if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- }
- break;
- case AUX_TRANSACTION_REPLY_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-static void process_write_request(
- struct aux_engine *engine,
- struct write_command_context *ctx)
-{
- enum aux_channel_operation_result operation_result;
-
- engine->funcs->submit_channel_request(engine, &ctx->request);
-
- operation_result = engine->funcs->get_channel_status(
- engine, &ctx->returned_byte);
-
- switch (operation_result) {
- case AUX_CHANNEL_OPERATION_SUCCEEDED:
- ctx->timed_out_retry_aux = 0;
- ctx->invalid_reply_retry_aux = 0;
-
- ctx->reply.length = ctx->returned_byte;
- ctx->reply.data = ctx->reply_data;
-
- process_write_reply(engine, ctx);
- break;
- case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
- ++ctx->invalid_reply_retry_aux;
-
- if (ctx->invalid_reply_retry_aux >
- AUX_INVALID_REPLY_RETRY_COUNTER) {
- ctx->status =
- I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
- ctx->operation_succeeded = false;
- } else
- udelay(400);
- break;
- case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
- ++ctx->timed_out_retry_aux;
-
- if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
- ctx->operation_succeeded = false;
- } else {
- /* DP 1.2a, table 2-58:
- * "S3: AUX Request CMD PENDING:
- * retry 3 times, with 400usec wait on each"
- * The HW timeout is set to 550usec,
- * so we should not wait here
- */
- }
- break;
- case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
- ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_HPD_DISCON;
- ctx->operation_succeeded = false;
- break;
- default:
- ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
- ctx->operation_succeeded = false;
- }
-}
-static bool write_command(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction)
-{
- struct write_command_context ctx;
-
- ctx.mot = middle_of_transaction;
- ctx.buffer = request->payload.data;
- ctx.current_write_length = request->payload.length;
- ctx.timed_out_retry_aux = 0;
- ctx.invalid_reply_retry_aux = 0;
- ctx.defer_retry_aux = 0;
- ctx.defer_retry_i2c = 0;
- ctx.ack_m_retry = 0;
- ctx.transaction_complete = false;
- ctx.operation_succeeded = true;
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- ctx.request.type = AUX_TRANSACTION_TYPE_DP;
- ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
- ctx.request.address = request->payload.address;
- } else if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
- ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
- ctx.request.action = middle_of_transaction ?
- I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
- I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
- ctx.request.address = request->payload.address >> 1;
- } else {
- /* in DAL2, there was no return in such case */
- BREAK_TO_DEBUGGER();
- return false;
- }
-
- ctx.request.delay = 0;
-
- ctx.max_defer_retry =
- (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
- engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
-
- do {
- ctx.request.data = ctx.buffer;
- ctx.request.length = ctx.current_write_length;
-
- process_write_request(engine, &ctx);
-
- request->status = ctx.status;
-
- if (ctx.operation_succeeded && !ctx.transaction_complete)
- if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
- msleep(engine->delay);
- } while (ctx.operation_succeeded && !ctx.transaction_complete);
-
- if (request->payload.address_space ==
- I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
- DC_LOG_I2C_AUX("WRITE: addr:0x%x value:0x%x Result:%d",
- request->payload.address,
- request->payload.data[0],
- ctx.operation_succeeded);
- }
-
- return ctx.operation_succeeded;
-}
-static bool end_of_transaction_command(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request)
-{
- struct i2caux_transaction_request dummy_request;
- uint8_t dummy_data;
-
- /* [tcheng] We only need to send the stop (read with MOT = 0)
- * for I2C-over-Aux, not native AUX
- */
-
- if (request->payload.address_space !=
- I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
- return false;
-
- dummy_request.operation = request->operation;
- dummy_request.payload.address_space = request->payload.address_space;
- dummy_request.payload.address = request->payload.address;
-
- /*
- * Add a dummy byte due to some receiver quirk
- * where one byte is sent along with MOT = 0.
- * Ideally this should be 0.
- */
-
- dummy_request.payload.length = 0;
- dummy_request.payload.data = &dummy_data;
-
- if (request->operation == I2CAUX_TRANSACTION_READ)
- return read_command(engine, &dummy_request, false);
- else
- return write_command(engine, &dummy_request, false);
-
- /* according Syed, it does not need now DoDummyMOT */
-}
-static bool submit_request(
- struct aux_engine *engine,
- struct i2caux_transaction_request *request,
- bool middle_of_transaction)
-{
-
- bool result;
- bool mot_used = true;
-
- switch (request->operation) {
- case I2CAUX_TRANSACTION_READ:
- result = read_command(engine, request, mot_used);
- break;
- case I2CAUX_TRANSACTION_WRITE:
- result = write_command(engine, request, mot_used);
- break;
- default:
- result = false;
- }
-
- /* [tcheng]
- * need to send stop for the last transaction to free up the AUX
- * if the above command fails, this would be the last transaction
- */
-
- if (!middle_of_transaction || !result)
- end_of_transaction_command(engine, request);
-
- /* mask AUX interrupt */
-
- return result;
-}
enum i2caux_engine_type get_engine_type(
- const struct aux_engine *engine)
+ const struct dce_aux *engine)
{
return I2CAUX_ENGINE_TYPE_AUX;
}
static bool acquire(
- struct aux_engine *engine,
+ struct dce_aux *engine,
struct ddc *ddc)
{
enum gpio_result result;
- if (engine->funcs->is_engine_available) {
- /*check whether SW could use the engine*/
- if (!engine->funcs->is_engine_available(engine))
- return false;
- }
+ if (!is_engine_available(engine))
+ return false;
result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
GPIO_DDC_CONFIG_TYPE_MODE_AUX);
@@ -884,7 +386,7 @@ static bool acquire(
if (result != GPIO_RESULT_OK)
return false;
- if (!engine->funcs->acquire_engine(engine)) {
+ if (!acquire_engine(engine)) {
dal_ddc_close(ddc);
return false;
}
@@ -894,21 +396,7 @@ static bool acquire(
return true;
}
-static const struct aux_engine_funcs aux_engine_funcs = {
- .acquire_engine = acquire_engine,
- .submit_channel_request = submit_channel_request,
- .process_channel_reply = process_channel_reply,
- .read_channel_reply = read_channel_reply,
- .get_channel_status = get_channel_status,
- .is_engine_available = is_engine_available,
- .release_engine = release_engine,
- .destroy_engine = dce110_engine_destroy,
- .submit_request = submit_request,
- .get_engine_type = get_engine_type,
- .acquire = acquire,
-};
-
-void dce110_engine_destroy(struct aux_engine **engine)
+void dce110_engine_destroy(struct dce_aux **engine)
{
struct aux_engine_dce110 *engine110 = FROM_AUX_ENGINE(*engine);
@@ -917,7 +405,7 @@ void dce110_engine_destroy(struct aux_engine **engine)
*engine = NULL;
}
-struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
+struct dce_aux *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_engine110,
struct dc_context *ctx,
uint32_t inst,
uint32_t timeout_period,
@@ -927,7 +415,6 @@ struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_eng
aux_engine110->base.ctx = ctx;
aux_engine110->base.delay = 0;
aux_engine110->base.max_defer_write_retry = 0;
- aux_engine110->base.funcs = &aux_engine_funcs;
aux_engine110->base.inst = inst;
aux_engine110->timeout_period = timeout_period;
aux_engine110->regs = regs;
@@ -935,3 +422,101 @@ struct aux_engine *dce110_aux_engine_construct(struct aux_engine_dce110 *aux_eng
return &aux_engine110->base;
}
+static enum i2caux_transaction_action i2caux_action_from_payload(struct aux_payload *payload)
+{
+ if (payload->i2c_over_aux) {
+ if (payload->write) {
+ if (payload->mot)
+ return I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT;
+ return I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
+ }
+ if (payload->mot)
+ return I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT;
+ return I2CAUX_TRANSACTION_ACTION_I2C_READ;
+ }
+ if (payload->write)
+ return I2CAUX_TRANSACTION_ACTION_DP_WRITE;
+ return I2CAUX_TRANSACTION_ACTION_DP_READ;
+}
+
+int dce_aux_transfer(struct ddc_service *ddc,
+ struct aux_payload *payload)
+{
+ struct ddc *ddc_pin = ddc->ddc_pin;
+ struct dce_aux *aux_engine;
+ enum aux_channel_operation_result operation_result;
+ struct aux_request_transaction_data aux_req;
+ struct aux_reply_transaction_data aux_rep;
+ uint8_t returned_bytes = 0;
+ int res = -1;
+ uint32_t status;
+
+ memset(&aux_req, 0, sizeof(aux_req));
+ memset(&aux_rep, 0, sizeof(aux_rep));
+
+ aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
+ acquire(aux_engine, ddc_pin);
+
+ if (payload->i2c_over_aux)
+ aux_req.type = AUX_TRANSACTION_TYPE_I2C;
+ else
+ aux_req.type = AUX_TRANSACTION_TYPE_DP;
+
+ aux_req.action = i2caux_action_from_payload(payload);
+
+ aux_req.address = payload->address;
+ aux_req.delay = payload->defer_delay * 10;
+ aux_req.length = payload->length;
+ aux_req.data = payload->data;
+
+ submit_channel_request(aux_engine, &aux_req);
+ operation_result = get_channel_status(aux_engine, &returned_bytes);
+
+ switch (operation_result) {
+ case AUX_CHANNEL_OPERATION_SUCCEEDED:
+ res = read_channel_reply(aux_engine, payload->length,
+ payload->data, payload->reply,
+ &status);
+ break;
+ case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON:
+ res = 0;
+ break;
+ case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN:
+ case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
+ case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
+ res = -1;
+ break;
+ }
+ release_engine(aux_engine);
+ return res;
+}
+
+#define AUX_RETRY_MAX 7
+
+bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
+ struct aux_payload *payload)
+{
+ int i, ret = 0;
+ uint8_t reply;
+ bool payload_reply = true;
+
+ if (!payload->reply) {
+ payload_reply = false;
+ payload->reply = &reply;
+ }
+
+ for (i = 0; i < AUX_RETRY_MAX; i++) {
+ ret = dce_aux_transfer(ddc, payload);
+
+ if (ret >= 0) {
+ if (*payload->reply == 0) {
+ if (!payload_reply)
+ payload->reply = NULL;
+ return true;
+ }
+ }
+
+ msleep(1);
+ }
+ return false;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
index f7caab85dc80..d27f22c05e4b 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.h
@@ -25,7 +25,9 @@
#ifndef __DAL_AUX_ENGINE_DCE110_H__
#define __DAL_AUX_ENGINE_DCE110_H__
-#include "aux_engine.h"
+
+#include "i2caux_interface.h"
+#include "inc/hw/aux_engine.h"
#define AUX_COMMON_REG_LIST(id)\
SRI(AUX_CONTROL, DP_AUX, id), \
@@ -75,8 +77,20 @@ enum { /* This is the timeout as defined in DP 1.2a,
*/
SW_AUX_TIMEOUT_PERIOD_MULTIPLIER = 4
};
+
+struct dce_aux {
+ uint32_t inst;
+ struct ddc *ddc;
+ struct dc_context *ctx;
+ /* following values are expressed in milliseconds */
+ uint32_t delay;
+ uint32_t max_defer_write_retry;
+
+ bool acquire_reset;
+};
+
struct aux_engine_dce110 {
- struct aux_engine base;
+ struct dce_aux base;
const struct dce110_aux_registers *regs;
struct {
uint32_t aux_control;
@@ -96,16 +110,22 @@ struct aux_engine_dce110_init_data {
const struct dce110_aux_registers *regs;
};
-struct aux_engine *dce110_aux_engine_construct(
+struct dce_aux *dce110_aux_engine_construct(
struct aux_engine_dce110 *aux_engine110,
struct dc_context *ctx,
uint32_t inst,
uint32_t timeout_period,
const struct dce110_aux_registers *regs);
-void dce110_engine_destroy(struct aux_engine **engine);
+void dce110_engine_destroy(struct dce_aux **engine);
bool dce110_aux_engine_acquire(
- struct aux_engine *aux_engine,
+ struct dce_aux *aux_engine,
struct ddc *ddc);
+
+int dce_aux_transfer(struct ddc_service *ddc,
+ struct aux_payload *cmd);
+
+bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
+ struct aux_payload *cmd);
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c
index afd287f08bc9..3c52a4fc921d 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c
@@ -194,8 +194,8 @@ static uint32_t get_max_pixel_clock_for_all_paths(struct dc_state *context)
if (pipe_ctx->top_pipe)
continue;
- if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk > max_pix_clk)
- max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk;
+ if (pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10 > max_pix_clk)
+ max_pix_clk = pipe_ctx->stream_res.pix_clk_params.requested_pix_clk_100hz / 10;
/* raise clock state for HBR3/2 if required. Confirmed with HW DCE/DPCS
* logic for HBR3 still needs Nominal (0.8V) on VDDC rail
@@ -257,7 +257,7 @@ static int dce_set_clock(
clk_mgr_dce->dentist_vco_freq_khz / 64);
/* Prepare to program display clock*/
- pxl_clk_params.target_pixel_clock = requested_clk_khz;
+ pxl_clk_params.target_pixel_clock_100hz = requested_clk_khz * 10;
pxl_clk_params.pll_id = CLOCK_SOURCE_ID_DFS;
if (clk_mgr_dce->dfs_bypass_active)
@@ -450,6 +450,42 @@ void dce_clock_read_ss_info(struct dce_clk_mgr *clk_mgr_dce)
}
}
+/**
+ * dce121_clock_patch_xgmi_ss_info() - Save XGMI spread spectrum info
+ * @clk_mgr: clock manager base structure
+ *
+ * Reads from VBIOS the XGMI spread spectrum info and saves it within
+ * the dce clock manager. This operation will overwrite the existing dprefclk
+ * SS values if the vBIOS query succeeds. Otherwise, it does nothing. It also
+ * sets the ->xgmi_enabled flag.
+ */
+void dce121_clock_patch_xgmi_ss_info(struct clk_mgr *clk_mgr)
+{
+ struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
+ enum bp_result result;
+ struct spread_spectrum_info info = { { 0 } };
+ struct dc_bios *bp = clk_mgr_dce->base.ctx->dc_bios;
+
+ clk_mgr_dce->xgmi_enabled = false;
+
+ result = bp->funcs->get_spread_spectrum_info(bp, AS_SIGNAL_TYPE_XGMI,
+ 0, &info);
+ if (result == BP_RESULT_OK && info.spread_spectrum_percentage != 0) {
+ clk_mgr_dce->xgmi_enabled = true;
+ clk_mgr_dce->ss_on_dprefclk = true;
+ clk_mgr_dce->dprefclk_ss_divider =
+ info.spread_percentage_divider;
+
+ if (info.type.CENTER_MODE == 0) {
+ /* Currently for DP Reference clock we
+ * need only SS percentage for
+ * downspread */
+ clk_mgr_dce->dprefclk_ss_percentage =
+ info.spread_spectrum_percentage;
+ }
+ }
+}
+
void dce110_fill_display_configs(
const struct dc_state *context,
struct dm_pp_display_configuration *pp_display_cfg)
@@ -483,18 +519,18 @@ void dce110_fill_display_configs(
cfg->src_height = stream->src.height;
cfg->src_width = stream->src.width;
cfg->ddi_channel_mapping =
- stream->sink->link->ddi_channel_mapping.raw;
+ stream->link->ddi_channel_mapping.raw;
cfg->transmitter =
- stream->sink->link->link_enc->transmitter;
+ stream->link->link_enc->transmitter;
cfg->link_settings.lane_count =
- stream->sink->link->cur_link_settings.lane_count;
+ stream->link->cur_link_settings.lane_count;
cfg->link_settings.link_rate =
- stream->sink->link->cur_link_settings.link_rate;
+ stream->link->cur_link_settings.link_rate;
cfg->link_settings.link_spread =
- stream->sink->link->cur_link_settings.link_spread;
+ stream->link->cur_link_settings.link_spread;
cfg->sym_clock = stream->phy_pix_clk;
/* Round v_refresh*/
- cfg->v_refresh = stream->timing.pix_clk_khz * 1000;
+ cfg->v_refresh = stream->timing.pix_clk_100hz * 100;
cfg->v_refresh /= stream->timing.h_total;
cfg->v_refresh = (cfg->v_refresh + stream->timing.v_total / 2)
/ stream->timing.v_total;
@@ -518,7 +554,7 @@ static uint32_t dce110_get_min_vblank_time_us(const struct dc_state *context)
- stream->timing.v_addressable);
vertical_blank_time = vertical_blank_in_pixels
- * 1000 / stream->timing.pix_clk_khz;
+ * 10000 / stream->timing.pix_clk_100hz;
if (min_vertical_blank_time > vertical_blank_time)
min_vertical_blank_time = vertical_blank_time;
@@ -612,7 +648,7 @@ static void dce11_pplib_apply_display_requirements(
pp_display_cfg->crtc_index =
pp_display_cfg->disp_configs[0].pipe_idx;
- pp_display_cfg->line_time_in_us = timing->h_total * 1000 / timing->pix_clk_khz;
+ pp_display_cfg->line_time_in_us = timing->h_total * 10000 / timing->pix_clk_100hz;
}
if (memcmp(&dc->current_state->pp_display_cfg, pp_display_cfg, sizeof(*pp_display_cfg)) != 0)
@@ -625,11 +661,11 @@ static void dce_update_clocks(struct clk_mgr *clk_mgr,
{
struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
struct dm_pp_power_level_change_request level_change_req;
- int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+ int patched_disp_clk = context->bw.dce.dispclk_khz;
/*TODO: W/A for dal3 linux, investigate why this works */
if (!clk_mgr_dce->dfs_bypass_active)
- context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
+ patched_disp_clk = patched_disp_clk * 115 / 100;
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
/* get max clock state from PPLIB */
@@ -639,13 +675,11 @@ static void dce_update_clocks(struct clk_mgr *clk_mgr,
clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
}
- if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
- context->bw.dce.dispclk_khz = dce_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
- clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+ if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) {
+ patched_disp_clk = dce_set_clock(clk_mgr, patched_disp_clk);
+ clk_mgr->clks.dispclk_khz = patched_disp_clk;
}
dce_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
-
- context->bw.dce.dispclk_khz = unpatched_disp_clk;
}
static void dce11_update_clocks(struct clk_mgr *clk_mgr,
@@ -676,11 +710,11 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr,
{
struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
struct dm_pp_power_level_change_request level_change_req;
- int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+ int patched_disp_clk = context->bw.dce.dispclk_khz;
/*TODO: W/A for dal3 linux, investigate why this works */
if (!clk_mgr_dce->dfs_bypass_active)
- context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
+ patched_disp_clk = patched_disp_clk * 115 / 100;
level_change_req.power_level = dce_get_required_clocks_state(clk_mgr, context);
/* get max clock state from PPLIB */
@@ -690,13 +724,11 @@ static void dce112_update_clocks(struct clk_mgr *clk_mgr,
clk_mgr_dce->cur_min_clks_state = level_change_req.power_level;
}
- if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
- context->bw.dce.dispclk_khz = dce112_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
- clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+ if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) {
+ patched_disp_clk = dce112_set_clock(clk_mgr, patched_disp_clk);
+ clk_mgr->clks.dispclk_khz = patched_disp_clk;
}
dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
-
- context->bw.dce.dispclk_khz = unpatched_disp_clk;
}
static void dce12_update_clocks(struct clk_mgr *clk_mgr,
@@ -706,17 +738,23 @@ static void dce12_update_clocks(struct clk_mgr *clk_mgr,
struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(clk_mgr);
struct dm_pp_clock_for_voltage_req clock_voltage_req = {0};
int max_pix_clk = get_max_pixel_clock_for_all_paths(context);
- int unpatched_disp_clk = context->bw.dce.dispclk_khz;
+ int patched_disp_clk = context->bw.dce.dispclk_khz;
/*TODO: W/A for dal3 linux, investigate why this works */
if (!clk_mgr_dce->dfs_bypass_active)
- context->bw.dce.dispclk_khz = context->bw.dce.dispclk_khz * 115 / 100;
+ patched_disp_clk = patched_disp_clk * 115 / 100;
- if (should_set_clock(safe_to_lower, context->bw.dce.dispclk_khz, clk_mgr->clks.dispclk_khz)) {
+ if (should_set_clock(safe_to_lower, patched_disp_clk, clk_mgr->clks.dispclk_khz)) {
clock_voltage_req.clk_type = DM_PP_CLOCK_TYPE_DISPLAY_CLK;
- clock_voltage_req.clocks_in_khz = context->bw.dce.dispclk_khz;
- context->bw.dce.dispclk_khz = dce112_set_clock(clk_mgr, context->bw.dce.dispclk_khz);
- clk_mgr->clks.dispclk_khz = context->bw.dce.dispclk_khz;
+ /*
+ * When xGMI is enabled, the display clk needs to be adjusted
+ * with the WAFL link's SS percentage.
+ */
+ if (clk_mgr_dce->xgmi_enabled)
+ patched_disp_clk = clk_mgr_adjust_dp_ref_freq_for_ss(
+ clk_mgr_dce, patched_disp_clk);
+ clock_voltage_req.clocks_in_khz = patched_disp_clk;
+ clk_mgr->clks.dispclk_khz = dce112_set_clock(clk_mgr, patched_disp_clk);
dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req);
}
@@ -729,8 +767,6 @@ static void dce12_update_clocks(struct clk_mgr *clk_mgr,
dm_pp_apply_clock_for_voltage_request(clk_mgr->ctx, &clock_voltage_req);
}
dce11_pplib_apply_display_requirements(clk_mgr->ctx->dc, context);
-
- context->bw.dce.dispclk_khz = unpatched_disp_clk;
}
static const struct clk_mgr_funcs dce120_funcs = {
@@ -882,6 +918,27 @@ struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx)
return &clk_mgr_dce->base;
}
+struct clk_mgr *dce121_clk_mgr_create(struct dc_context *ctx)
+{
+ struct dce_clk_mgr *clk_mgr_dce = kzalloc(sizeof(*clk_mgr_dce),
+ GFP_KERNEL);
+
+ if (clk_mgr_dce == NULL) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ memcpy(clk_mgr_dce->max_clks_by_state, dce120_max_clks_by_state,
+ sizeof(dce120_max_clks_by_state));
+
+ dce_clk_mgr_construct(clk_mgr_dce, ctx, NULL, NULL, NULL);
+
+ clk_mgr_dce->dprefclk_khz = 625000;
+ clk_mgr_dce->base.funcs = &dce120_funcs;
+
+ return &clk_mgr_dce->base;
+}
+
void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr)
{
struct dce_clk_mgr *clk_mgr_dce = TO_DCE_CLK_MGR(*clk_mgr);
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h
index 3bceb31d910d..c8f8c442142a 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.h
@@ -94,11 +94,37 @@ struct dce_clk_mgr {
* This is basically "Crystal Frequency In KHz" (XTALIN) frequency */
int dfs_bypass_disp_clk;
- /* Flag for Enabled SS on DPREFCLK */
+ /**
+ * @ss_on_dprefclk:
+ *
+ * True if spread spectrum is enabled on the DP ref clock.
+ */
bool ss_on_dprefclk;
- /* DPREFCLK SS percentage (if down-spread enabled) */
+
+ /**
+ * @xgmi_enabled:
+ *
+ * True if xGMI is enabled. On VG20, both audio and display clocks need
+ * to be adjusted with the WAFL link's SS info if xGMI is enabled.
+ */
+ bool xgmi_enabled;
+
+ /**
+ * @dprefclk_ss_percentage:
+ *
+ * DPREFCLK SS percentage (if down-spread enabled).
+ *
+ * Note that if XGMI is enabled, the SS info (percentage and divider)
+ * from the WAFL link is used instead. This is decided during
+ * dce_clk_mgr initialization.
+ */
int dprefclk_ss_percentage;
- /* DPREFCLK SS percentage Divider (100 or 1000) */
+
+ /**
+ * @dprefclk_ss_divider:
+ *
+ * DPREFCLK SS percentage Divider (100 or 1000).
+ */
int dprefclk_ss_divider;
int dprefclk_khz;
@@ -163,6 +189,9 @@ struct clk_mgr *dce112_clk_mgr_create(
struct clk_mgr *dce120_clk_mgr_create(struct dc_context *ctx);
+struct clk_mgr *dce121_clk_mgr_create(struct dc_context *ctx);
+void dce121_clock_patch_xgmi_ss_info(struct clk_mgr *clk_mgr);
+
void dce_clk_mgr_destroy(struct clk_mgr **clk_mgr);
int dentist_get_divider_from_did(int did);
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
index 723ce80ed89c..c67e90e5c339 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
@@ -108,28 +108,28 @@ static const struct spread_spectrum_data *get_ss_data_entry(
}
/**
-* Function: calculate_fb_and_fractional_fb_divider
-*
-* * DESCRIPTION: Calculates feedback and fractional feedback dividers values
-*
-*PARAMETERS:
-* targetPixelClock Desired frequency in 10 KHz
-* ref_divider Reference divider (already known)
-* postDivider Post Divider (already known)
-* feedback_divider_param Pointer where to store
-* calculated feedback divider value
-* fract_feedback_divider_param Pointer where to store
-* calculated fract feedback divider value
-*
-*RETURNS:
-* It fills the locations pointed by feedback_divider_param
-* and fract_feedback_divider_param
-* It returns - true if feedback divider not 0
-* - false should never happen)
-*/
+ * Function: calculate_fb_and_fractional_fb_divider
+ *
+ * * DESCRIPTION: Calculates feedback and fractional feedback dividers values
+ *
+ *PARAMETERS:
+ * targetPixelClock Desired frequency in 100 Hz
+ * ref_divider Reference divider (already known)
+ * postDivider Post Divider (already known)
+ * feedback_divider_param Pointer where to store
+ * calculated feedback divider value
+ * fract_feedback_divider_param Pointer where to store
+ * calculated fract feedback divider value
+ *
+ *RETURNS:
+ * It fills the locations pointed by feedback_divider_param
+ * and fract_feedback_divider_param
+ * It returns - true if feedback divider not 0
+ * - false should never happen)
+ */
static bool calculate_fb_and_fractional_fb_divider(
struct calc_pll_clock_source *calc_pll_cs,
- uint32_t target_pix_clk_khz,
+ uint32_t target_pix_clk_100hz,
uint32_t ref_divider,
uint32_t post_divider,
uint32_t *feedback_divider_param,
@@ -138,11 +138,11 @@ static bool calculate_fb_and_fractional_fb_divider(
uint64_t feedback_divider;
feedback_divider =
- (uint64_t)target_pix_clk_khz * ref_divider * post_divider;
+ (uint64_t)target_pix_clk_100hz * ref_divider * post_divider;
feedback_divider *= 10;
/* additional factor, since we divide by 10 afterwards */
feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor);
- feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz);
+ feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz * 10ull);
/*Round to the number of precision
* The following code replace the old code (ullfeedbackDivider + 5)/10
@@ -195,36 +195,36 @@ static bool calc_fb_divider_checking_tolerance(
{
uint32_t feedback_divider;
uint32_t fract_feedback_divider;
- uint32_t actual_calculated_clock_khz;
+ uint32_t actual_calculated_clock_100hz;
uint32_t abs_err;
- uint64_t actual_calc_clk_khz;
+ uint64_t actual_calc_clk_100hz;
calculate_fb_and_fractional_fb_divider(
calc_pll_cs,
- pll_settings->adjusted_pix_clk,
+ pll_settings->adjusted_pix_clk_100hz,
ref_divider,
post_divider,
&feedback_divider,
&fract_feedback_divider);
/*Actual calculated value*/
- actual_calc_clk_khz = (uint64_t)feedback_divider *
+ actual_calc_clk_100hz = (uint64_t)feedback_divider *
calc_pll_cs->fract_fb_divider_factor +
fract_feedback_divider;
- actual_calc_clk_khz *= calc_pll_cs->ref_freq_khz;
- actual_calc_clk_khz =
- div_u64(actual_calc_clk_khz,
+ actual_calc_clk_100hz *= calc_pll_cs->ref_freq_khz * 10;
+ actual_calc_clk_100hz =
+ div_u64(actual_calc_clk_100hz,
ref_divider * post_divider *
calc_pll_cs->fract_fb_divider_factor);
- actual_calculated_clock_khz = (uint32_t)(actual_calc_clk_khz);
+ actual_calculated_clock_100hz = (uint32_t)(actual_calc_clk_100hz);
- abs_err = (actual_calculated_clock_khz >
- pll_settings->adjusted_pix_clk)
- ? actual_calculated_clock_khz -
- pll_settings->adjusted_pix_clk
- : pll_settings->adjusted_pix_clk -
- actual_calculated_clock_khz;
+ abs_err = (actual_calculated_clock_100hz >
+ pll_settings->adjusted_pix_clk_100hz)
+ ? actual_calculated_clock_100hz -
+ pll_settings->adjusted_pix_clk_100hz
+ : pll_settings->adjusted_pix_clk_100hz -
+ actual_calculated_clock_100hz;
if (abs_err <= tolerance) {
/*found good values*/
@@ -233,10 +233,10 @@ static bool calc_fb_divider_checking_tolerance(
pll_settings->feedback_divider = feedback_divider;
pll_settings->fract_feedback_divider = fract_feedback_divider;
pll_settings->pix_clk_post_divider = post_divider;
- pll_settings->calculated_pix_clk =
- actual_calculated_clock_khz;
+ pll_settings->calculated_pix_clk_100hz =
+ actual_calculated_clock_100hz;
pll_settings->vco_freq =
- actual_calculated_clock_khz * post_divider;
+ actual_calculated_clock_100hz * post_divider / 10;
return true;
}
return false;
@@ -257,8 +257,8 @@ static bool calc_pll_dividers_in_range(
/* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
* This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
- tolerance = (pll_settings->adjusted_pix_clk * err_tolerance) /
- 10000;
+ tolerance = (pll_settings->adjusted_pix_clk_100hz * err_tolerance) /
+ 100000;
if (tolerance < CALC_PLL_CLK_SRC_ERR_TOLERANCE)
tolerance = CALC_PLL_CLK_SRC_ERR_TOLERANCE;
@@ -294,7 +294,7 @@ static uint32_t calculate_pixel_clock_pll_dividers(
uint32_t min_ref_divider;
uint32_t max_ref_divider;
- if (pll_settings->adjusted_pix_clk == 0) {
+ if (pll_settings->adjusted_pix_clk_100hz == 0) {
DC_LOG_ERROR(
"%s Bad requested pixel clock", __func__);
return MAX_PLL_CALC_ERROR;
@@ -306,21 +306,21 @@ static uint32_t calculate_pixel_clock_pll_dividers(
max_post_divider = pll_settings->pix_clk_post_divider;
} else {
min_post_divider = calc_pll_cs->min_pix_clock_pll_post_divider;
- if (min_post_divider * pll_settings->adjusted_pix_clk <
- calc_pll_cs->min_vco_khz) {
- min_post_divider = calc_pll_cs->min_vco_khz /
- pll_settings->adjusted_pix_clk;
+ if (min_post_divider * pll_settings->adjusted_pix_clk_100hz <
+ calc_pll_cs->min_vco_khz * 10) {
+ min_post_divider = calc_pll_cs->min_vco_khz * 10 /
+ pll_settings->adjusted_pix_clk_100hz;
if ((min_post_divider *
- pll_settings->adjusted_pix_clk) <
- calc_pll_cs->min_vco_khz)
+ pll_settings->adjusted_pix_clk_100hz) <
+ calc_pll_cs->min_vco_khz * 10)
min_post_divider++;
}
max_post_divider = calc_pll_cs->max_pix_clock_pll_post_divider;
- if (max_post_divider * pll_settings->adjusted_pix_clk
- > calc_pll_cs->max_vco_khz)
- max_post_divider = calc_pll_cs->max_vco_khz /
- pll_settings->adjusted_pix_clk;
+ if (max_post_divider * pll_settings->adjusted_pix_clk_100hz
+ > calc_pll_cs->max_vco_khz * 10)
+ max_post_divider = calc_pll_cs->max_vco_khz * 10 /
+ pll_settings->adjusted_pix_clk_100hz;
}
/* 2) Find Reference divider ranges
@@ -392,47 +392,47 @@ static bool pll_adjust_pix_clk(
struct pixel_clk_params *pix_clk_params,
struct pll_settings *pll_settings)
{
- uint32_t actual_pix_clk_khz = 0;
- uint32_t requested_clk_khz = 0;
+ uint32_t actual_pix_clk_100hz = 0;
+ uint32_t requested_clk_100hz = 0;
struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params = {
0 };
enum bp_result bp_result;
switch (pix_clk_params->signal_type) {
case SIGNAL_TYPE_HDMI_TYPE_A: {
- requested_clk_khz = pix_clk_params->requested_pix_clk;
+ requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
if (pix_clk_params->pixel_encoding != PIXEL_ENCODING_YCBCR422) {
switch (pix_clk_params->color_depth) {
case COLOR_DEPTH_101010:
- requested_clk_khz = (requested_clk_khz * 5) >> 2;
+ requested_clk_100hz = (requested_clk_100hz * 5) >> 2;
break; /* x1.25*/
case COLOR_DEPTH_121212:
- requested_clk_khz = (requested_clk_khz * 6) >> 2;
+ requested_clk_100hz = (requested_clk_100hz * 6) >> 2;
break; /* x1.5*/
case COLOR_DEPTH_161616:
- requested_clk_khz = requested_clk_khz * 2;
+ requested_clk_100hz = requested_clk_100hz * 2;
break; /* x2.0*/
default:
break;
}
}
- actual_pix_clk_khz = requested_clk_khz;
+ actual_pix_clk_100hz = requested_clk_100hz;
}
break;
case SIGNAL_TYPE_DISPLAY_PORT:
case SIGNAL_TYPE_DISPLAY_PORT_MST:
case SIGNAL_TYPE_EDP:
- requested_clk_khz = pix_clk_params->requested_sym_clk;
- actual_pix_clk_khz = pix_clk_params->requested_pix_clk;
+ requested_clk_100hz = pix_clk_params->requested_sym_clk * 10;
+ actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
break;
default:
- requested_clk_khz = pix_clk_params->requested_pix_clk;
- actual_pix_clk_khz = pix_clk_params->requested_pix_clk;
+ requested_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
+ actual_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
break;
}
- bp_adjust_pixel_clock_params.pixel_clock = requested_clk_khz;
+ bp_adjust_pixel_clock_params.pixel_clock = requested_clk_100hz / 10;
bp_adjust_pixel_clock_params.
encoder_object_id = pix_clk_params->encoder_object_id;
bp_adjust_pixel_clock_params.signal_type = pix_clk_params->signal_type;
@@ -441,9 +441,9 @@ static bool pll_adjust_pix_clk(
bp_result = clk_src->bios->funcs->adjust_pixel_clock(
clk_src->bios, &bp_adjust_pixel_clock_params);
if (bp_result == BP_RESULT_OK) {
- pll_settings->actual_pix_clk = actual_pix_clk_khz;
- pll_settings->adjusted_pix_clk =
- bp_adjust_pixel_clock_params.adjusted_pixel_clock;
+ pll_settings->actual_pix_clk_100hz = actual_pix_clk_100hz;
+ pll_settings->adjusted_pix_clk_100hz =
+ bp_adjust_pixel_clock_params.adjusted_pixel_clock * 10;
pll_settings->reference_divider =
bp_adjust_pixel_clock_params.reference_divider;
pll_settings->pix_clk_post_divider =
@@ -490,7 +490,7 @@ static uint32_t dce110_get_pix_clk_dividers_helper (
const struct spread_spectrum_data *ss_data = get_ss_data_entry(
clk_src,
pix_clk_params->signal_type,
- pll_settings->adjusted_pix_clk);
+ pll_settings->adjusted_pix_clk_100hz / 10);
if (NULL != ss_data)
pll_settings->ss_percentage = ss_data->percentage;
@@ -502,13 +502,13 @@ static uint32_t dce110_get_pix_clk_dividers_helper (
* to continue. */
DC_LOG_ERROR(
"%s: Failed to adjust pixel clock!!", __func__);
- pll_settings->actual_pix_clk =
- pix_clk_params->requested_pix_clk;
- pll_settings->adjusted_pix_clk =
- pix_clk_params->requested_pix_clk;
+ pll_settings->actual_pix_clk_100hz =
+ pix_clk_params->requested_pix_clk_100hz;
+ pll_settings->adjusted_pix_clk_100hz =
+ pix_clk_params->requested_pix_clk_100hz;
if (dc_is_dp_signal(pix_clk_params->signal_type))
- pll_settings->adjusted_pix_clk = 100000;
+ pll_settings->adjusted_pix_clk_100hz = 1000000;
}
/* Calculate Dividers */
@@ -533,28 +533,28 @@ static void dce112_get_pix_clk_dividers_helper (
struct pll_settings *pll_settings,
struct pixel_clk_params *pix_clk_params)
{
- uint32_t actualPixelClockInKHz;
+ uint32_t actual_pixel_clock_100hz;
- actualPixelClockInKHz = pix_clk_params->requested_pix_clk;
+ actual_pixel_clock_100hz = pix_clk_params->requested_pix_clk_100hz;
/* Calculate Dividers */
if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
switch (pix_clk_params->color_depth) {
case COLOR_DEPTH_101010:
- actualPixelClockInKHz = (actualPixelClockInKHz * 5) >> 2;
+ actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 5) >> 2;
break;
case COLOR_DEPTH_121212:
- actualPixelClockInKHz = (actualPixelClockInKHz * 6) >> 2;
+ actual_pixel_clock_100hz = (actual_pixel_clock_100hz * 6) >> 2;
break;
case COLOR_DEPTH_161616:
- actualPixelClockInKHz = actualPixelClockInKHz * 2;
+ actual_pixel_clock_100hz = actual_pixel_clock_100hz * 2;
break;
default:
break;
}
}
- pll_settings->actual_pix_clk = actualPixelClockInKHz;
- pll_settings->adjusted_pix_clk = actualPixelClockInKHz;
- pll_settings->calculated_pix_clk = pix_clk_params->requested_pix_clk;
+ pll_settings->actual_pix_clk_100hz = actual_pixel_clock_100hz;
+ pll_settings->adjusted_pix_clk_100hz = actual_pixel_clock_100hz;
+ pll_settings->calculated_pix_clk_100hz = pix_clk_params->requested_pix_clk_100hz;
}
static uint32_t dce110_get_pix_clk_dividers(
@@ -567,7 +567,7 @@ static uint32_t dce110_get_pix_clk_dividers(
DC_LOGGER_INIT();
if (pix_clk_params == NULL || pll_settings == NULL
- || pix_clk_params->requested_pix_clk == 0) {
+ || pix_clk_params->requested_pix_clk_100hz == 0) {
DC_LOG_ERROR(
"%s: Invalid parameters!!\n", __func__);
return pll_calc_error;
@@ -577,10 +577,10 @@ static uint32_t dce110_get_pix_clk_dividers(
if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
- pll_settings->adjusted_pix_clk = clk_src->ext_clk_khz;
- pll_settings->calculated_pix_clk = clk_src->ext_clk_khz;
- pll_settings->actual_pix_clk =
- pix_clk_params->requested_pix_clk;
+ pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10;
+ pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
+ pll_settings->actual_pix_clk_100hz =
+ pix_clk_params->requested_pix_clk_100hz;
return 0;
}
@@ -599,7 +599,7 @@ static uint32_t dce112_get_pix_clk_dividers(
DC_LOGGER_INIT();
if (pix_clk_params == NULL || pll_settings == NULL
- || pix_clk_params->requested_pix_clk == 0) {
+ || pix_clk_params->requested_pix_clk_100hz == 0) {
DC_LOG_ERROR(
"%s: Invalid parameters!!\n", __func__);
return -1;
@@ -609,10 +609,10 @@ static uint32_t dce112_get_pix_clk_dividers(
if (cs->id == CLOCK_SOURCE_ID_DP_DTO ||
cs->id == CLOCK_SOURCE_ID_EXTERNAL) {
- pll_settings->adjusted_pix_clk = clk_src->ext_clk_khz;
- pll_settings->calculated_pix_clk = clk_src->ext_clk_khz;
- pll_settings->actual_pix_clk =
- pix_clk_params->requested_pix_clk;
+ pll_settings->adjusted_pix_clk_100hz = clk_src->ext_clk_khz * 10;
+ pll_settings->calculated_pix_clk_100hz = clk_src->ext_clk_khz * 10;
+ pll_settings->actual_pix_clk_100hz =
+ pix_clk_params->requested_pix_clk_100hz;
return -1;
}
@@ -714,7 +714,7 @@ static bool enable_spread_spectrum(
ss_data = get_ss_data_entry(
clk_src,
signal,
- pll_settings->calculated_pix_clk);
+ pll_settings->calculated_pix_clk_100hz / 10);
/* Pixel clock PLL has been programmed to generate desired pixel clock,
* now enable SS on pixel clock */
@@ -853,7 +853,7 @@ static bool dce110_program_pix_clk(
/*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
bp_pc_params.controller_id = pix_clk_params->controller_id;
bp_pc_params.pll_id = clock_source->id;
- bp_pc_params.target_pixel_clock = pll_settings->actual_pix_clk;
+ bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
bp_pc_params.signal_type = pix_clk_params->signal_type;
@@ -903,12 +903,12 @@ static bool dce112_program_pix_clk(
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) {
unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
- unsigned dp_dto_ref_kHz = 700000;
- unsigned clock_kHz = pll_settings->actual_pix_clk;
+ unsigned dp_dto_ref_100hz = 7000000;
+ unsigned clock_100hz = pll_settings->actual_pix_clk_100hz;
/* Set DTO values: phase = target clock, modulo = reference clock */
- REG_WRITE(PHASE[inst], clock_kHz);
- REG_WRITE(MODULO[inst], dp_dto_ref_kHz);
+ REG_WRITE(PHASE[inst], clock_100hz);
+ REG_WRITE(MODULO[inst], dp_dto_ref_100hz);
/* Enable DTO */
REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
@@ -927,7 +927,7 @@ static bool dce112_program_pix_clk(
/*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
bp_pc_params.controller_id = pix_clk_params->controller_id;
bp_pc_params.pll_id = clock_source->id;
- bp_pc_params.target_pixel_clock = pll_settings->actual_pix_clk;
+ bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
bp_pc_params.signal_type = pix_clk_params->signal_type;
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
index dea40b322191..c2926cf19dee 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
@@ -51,7 +51,6 @@
#define PSR_SET_WAITLOOP 0x31
#define MCP_INIT_DMCU 0x88
#define MCP_INIT_IRAM 0x89
-#define MCP_DMCU_VERSION 0x90
#define MASTER_COMM_CNTL_REG__MASTER_COMM_INTERRUPT_MASK 0x00000001L
static bool dce_dmcu_init(struct dmcu *dmcu)
@@ -317,38 +316,11 @@ static void dce_get_psr_wait_loop(
}
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
-static void dcn10_get_dmcu_state(struct dmcu *dmcu)
-{
- struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
- uint32_t dmcu_state_offset = 0xf6;
-
- /* Enable write access to IRAM */
- REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
- IRAM_HOST_ACCESS_EN, 1,
- IRAM_RD_ADDR_AUTO_INC, 1);
-
- REG_WAIT(DMU_MEM_PWR_CNTL, DMCU_IRAM_MEM_PWR_STATE, 0, 2, 10);
-
- /* Write address to IRAM_RD_ADDR in DMCU_IRAM_RD_CTRL */
- REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_state_offset);
-
- /* Read data from IRAM_RD_DATA in DMCU_IRAM_RD_DATA*/
- dmcu->dmcu_state = REG_READ(DMCU_IRAM_RD_DATA);
-
- /* Disable write access to IRAM to allow dynamic sleep state */
- REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
- IRAM_HOST_ACCESS_EN, 0,
- IRAM_RD_ADDR_AUTO_INC, 0);
-}
-
static void dcn10_get_dmcu_version(struct dmcu *dmcu)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
uint32_t dmcu_version_offset = 0xf1;
- /* Clear scratch */
- REG_WRITE(DC_DMCU_SCRATCH, 0);
-
/* Enable write access to IRAM */
REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
IRAM_HOST_ACCESS_EN, 1,
@@ -359,85 +331,74 @@ static void dcn10_get_dmcu_version(struct dmcu *dmcu)
/* Write address to IRAM_RD_ADDR and read from DATA register */
REG_WRITE(DMCU_IRAM_RD_CTRL, dmcu_version_offset);
dmcu->dmcu_version.interface_version = REG_READ(DMCU_IRAM_RD_DATA);
- dmcu->dmcu_version.year = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) |
+ dmcu->dmcu_version.abm_version = REG_READ(DMCU_IRAM_RD_DATA);
+ dmcu->dmcu_version.psr_version = REG_READ(DMCU_IRAM_RD_DATA);
+ dmcu->dmcu_version.build_version = ((REG_READ(DMCU_IRAM_RD_DATA) << 8) |
REG_READ(DMCU_IRAM_RD_DATA));
- dmcu->dmcu_version.month = REG_READ(DMCU_IRAM_RD_DATA);
- dmcu->dmcu_version.date = REG_READ(DMCU_IRAM_RD_DATA);
/* Disable write access to IRAM to allow dynamic sleep state */
REG_UPDATE_2(DMCU_RAM_ACCESS_CTRL,
IRAM_HOST_ACCESS_EN, 0,
IRAM_RD_ADDR_AUTO_INC, 0);
-
- /* Send MCP command message to DMCU to get version reply from FW.
- * We expect this version should match the one in IRAM, otherwise
- * something is wrong with DMCU and we should fail and disable UC.
- */
- REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
-
- /* Set command to get DMCU version from microcontroller */
- REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
- MCP_DMCU_VERSION);
-
- /* Notify microcontroller of new command */
- REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
-
- /* Ensure command has been executed before continuing */
- REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
-
- /* Somehow version does not match, so fail and return version 0 */
- if (dmcu->dmcu_version.interface_version != REG_READ(DC_DMCU_SCRATCH))
- dmcu->dmcu_version.interface_version = 0;
}
static bool dcn10_dmcu_init(struct dmcu *dmcu)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
+ bool status = false;
- /* DMCU FW should populate the scratch register if running */
- if (REG_READ(DC_DMCU_SCRATCH) == 0)
- return false;
-
- /* Check state is uninitialized */
- dcn10_get_dmcu_state(dmcu);
-
- /* If microcontroller is already initialized, do nothing */
- if (dmcu->dmcu_state == DMCU_RUNNING)
- return true;
-
- /* Retrieve and cache the DMCU firmware version. */
- dcn10_get_dmcu_version(dmcu);
-
- /* Check interface version to confirm firmware is loaded and running */
- if (dmcu->dmcu_version.interface_version == 0)
- return false;
+ /* Definition of DC_DMCU_SCRATCH
+ * 0 : firmare not loaded
+ * 1 : PSP load DMCU FW but not initialized
+ * 2 : Firmware already initialized
+ */
+ dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH);
- /* Wait until microcontroller is ready to process interrupt */
- REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
+ switch (dmcu->dmcu_state) {
+ case DMCU_UNLOADED:
+ status = false;
+ break;
+ case DMCU_LOADED_UNINITIALIZED:
+ /* Wait until microcontroller is ready to process interrupt */
+ REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
- /* Set initialized ramping boundary value */
- REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF);
+ /* Set initialized ramping boundary value */
+ REG_WRITE(MASTER_COMM_DATA_REG1, 0xFFFF);
- /* Set command to initialize microcontroller */
- REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
+ /* Set command to initialize microcontroller */
+ REG_UPDATE(MASTER_COMM_CMD_REG, MASTER_COMM_CMD_REG_BYTE0,
MCP_INIT_DMCU);
- /* Notify microcontroller of new command */
- REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
+ /* Notify microcontroller of new command */
+ REG_UPDATE(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 1);
- /* Ensure command has been executed before continuing */
- REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
+ /* Ensure command has been executed before continuing */
+ REG_WAIT(MASTER_COMM_CNTL_REG, MASTER_COMM_INTERRUPT, 0, 100, 800);
- // Check state is initialized
- dcn10_get_dmcu_state(dmcu);
+ // Check state is initialized
+ dmcu->dmcu_state = REG_READ(DC_DMCU_SCRATCH);
- // If microcontroller is not in running state, fail
- if (dmcu->dmcu_state != DMCU_RUNNING)
- return false;
+ // If microcontroller is not in running state, fail
+ if (dmcu->dmcu_state == DMCU_RUNNING) {
+ /* Retrieve and cache the DMCU firmware version. */
+ dcn10_get_dmcu_version(dmcu);
+ status = true;
+ } else
+ status = false;
- return true;
+ break;
+ case DMCU_RUNNING:
+ status = true;
+ break;
+ default:
+ status = false;
+ break;
+ }
+
+ return status;
}
+
static bool dcn10_dmcu_load_iram(struct dmcu *dmcu,
unsigned int start_offset,
const char *src,
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
index c83a7f05f14c..956bdf14503f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h
@@ -133,6 +133,10 @@
SR(DCHUB_AGP_TOP), \
BL_REG_LIST()
+#define HWSEQ_VG20_REG_LIST() \
+ HWSEQ_DCE120_REG_LIST(),\
+ MMHUB_SR(MC_VM_XGMI_LFB_CNTL)
+
#define HWSEQ_DCE112_REG_LIST() \
HWSEQ_DCE10_REG_LIST(), \
HWSEQ_PIXEL_RATE_REG_LIST(CRTC), \
@@ -298,6 +302,7 @@ struct dce_hwseq_registers {
uint32_t MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB;
uint32_t MC_VM_SYSTEM_APERTURE_LOW_ADDR;
uint32_t MC_VM_SYSTEM_APERTURE_HIGH_ADDR;
+ uint32_t MC_VM_XGMI_LFB_CNTL;
uint32_t AZALIA_AUDIO_DTO;
uint32_t AZALIA_CONTROLLER_CLOCK_GATING;
};
@@ -382,6 +387,11 @@ struct dce_hwseq_registers {
HWS_SF(, LVTMA_PWRSEQ_CNTL, LVTMA_BLON, mask_sh), \
HWS_SF(, LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R, mask_sh)
+#define HWSEQ_VG20_MASK_SH_LIST(mask_sh)\
+ HWSEQ_DCE12_MASK_SH_LIST(mask_sh),\
+ HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_LFB_REGION, mask_sh),\
+ HWS_SF(, MC_VM_XGMI_LFB_CNTL, PF_MAX_REGION, mask_sh)
+
#define HWSEQ_DCN_MASK_SH_LIST(mask_sh)\
HWSEQ_PIXEL_RATE_MASK_SH_LIST(mask_sh, OTG0_),\
HWS_SF1(OTG0_, PHYPLL_PIXEL_RATE_CNTL, PHYPLL_PIXEL_RATE_SOURCE, mask_sh), \
@@ -470,6 +480,8 @@ struct dce_hwseq_registers {
type PHYSICAL_PAGE_NUMBER_MSB;\
type PHYSICAL_PAGE_NUMBER_LSB;\
type LOGICAL_ADDR; \
+ type PF_LFB_REGION;\
+ type PF_MAX_REGION;\
type ENABLE_L1_TLB;\
type SYSTEM_ACCESS_MODE;\
type LVTMA_BLON;\
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
index 3e18ea84b1f9..314c04a915d2 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
@@ -599,12 +599,12 @@ bool dce110_link_encoder_validate_dvi_output(
if ((connector_signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
connector_signal == SIGNAL_TYPE_HDMI_TYPE_A) &&
signal != SIGNAL_TYPE_HDMI_TYPE_A &&
- crtc_timing->pix_clk_khz > TMDS_MAX_PIXEL_CLOCK)
+ crtc_timing->pix_clk_100hz > (TMDS_MAX_PIXEL_CLOCK * 10))
return false;
- if (crtc_timing->pix_clk_khz < TMDS_MIN_PIXEL_CLOCK)
+ if (crtc_timing->pix_clk_100hz < (TMDS_MIN_PIXEL_CLOCK * 10))
return false;
- if (crtc_timing->pix_clk_khz > max_pixel_clock)
+ if (crtc_timing->pix_clk_100hz > (max_pixel_clock * 10))
return false;
/* DVI supports 6/8bpp single-link and 10/16bpp dual-link */
@@ -788,7 +788,7 @@ bool dce110_link_encoder_validate_output_with_stream(
case SIGNAL_TYPE_DVI_DUAL_LINK:
is_valid = dce110_link_encoder_validate_dvi_output(
enc110,
- stream->sink->link->connector_signal,
+ stream->link->connector_signal,
stream->signal,
&stream->timing);
break;
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
index cce0d18f91da..1fa2d4fd7a35 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
@@ -288,9 +288,18 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
#endif
struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
-
+ struct dc_crtc_timing hw_crtc_timing = *crtc_timing;
+ if (hw_crtc_timing.flags.INTERLACE) {
+ /*the input timing is in VESA spec format with Interlace flag =1*/
+ hw_crtc_timing.v_total /= 2;
+ hw_crtc_timing.v_border_top /= 2;
+ hw_crtc_timing.v_addressable /= 2;
+ hw_crtc_timing.v_border_bottom /= 2;
+ hw_crtc_timing.v_front_porch /= 2;
+ hw_crtc_timing.v_sync_width /= 2;
+ }
/* set pixel encoding */
- switch (crtc_timing->pixel_encoding) {
+ switch (hw_crtc_timing.pixel_encoding) {
case PIXEL_ENCODING_YCBCR422:
REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING,
DP_PIXEL_ENCODING_TYPE_YCBCR422);
@@ -299,8 +308,8 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING,
DP_PIXEL_ENCODING_TYPE_YCBCR444);
- if (crtc_timing->flags.Y_ONLY)
- if (crtc_timing->display_color_depth != COLOR_DEPTH_666)
+ if (hw_crtc_timing.flags.Y_ONLY)
+ if (hw_crtc_timing.display_color_depth != COLOR_DEPTH_666)
/* HW testing only, no use case yet.
* Color depth of Y-only could be
* 8, 10, 12, 16 bits */
@@ -335,7 +344,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
/* set color depth */
- switch (crtc_timing->display_color_depth) {
+ switch (hw_crtc_timing.display_color_depth) {
case COLOR_DEPTH_666:
REG_UPDATE(DP_PIXEL_FORMAT, DP_COMPONENT_DEPTH,
0);
@@ -363,7 +372,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
- switch (crtc_timing->display_color_depth) {
+ switch (hw_crtc_timing.display_color_depth) {
case COLOR_DEPTH_666:
colorimetry_bpc = 0;
break;
@@ -401,9 +410,9 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
misc0 = misc0 | 0x8; /* bit3=1, bit4=0 */
misc1 = misc1 & ~0x80; /* bit7 = 0*/
dynamic_range_ycbcr = 0; /*bt601*/
- if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */
- else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444)
+ else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444)
misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */
break;
case COLOR_SPACE_YCBCR709:
@@ -411,9 +420,9 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
misc0 = misc0 | 0x18; /* bit3=1, bit4=1 */
misc1 = misc1 & ~0x80; /* bit7 = 0*/
dynamic_range_ycbcr = 1; /*bt709*/
- if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR422)
+ if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
misc0 = misc0 | 0x2; /* bit2=0, bit1=1 */
- else if (crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR444)
+ else if (hw_crtc_timing.pixel_encoding == PIXEL_ENCODING_YCBCR444)
misc0 = misc0 | 0x4; /* bit2=1, bit1=0 */
break;
case COLOR_SPACE_2020_RGB_LIMITEDRANGE:
@@ -453,27 +462,27 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
*/
if (REG(DP_MSA_TIMING_PARAM1))
REG_SET_2(DP_MSA_TIMING_PARAM1, 0,
- DP_MSA_HTOTAL, crtc_timing->h_total,
- DP_MSA_VTOTAL, crtc_timing->v_total);
+ DP_MSA_HTOTAL, hw_crtc_timing.h_total,
+ DP_MSA_VTOTAL, hw_crtc_timing.v_total);
#endif
/* calcuate from vesa timing parameters
* h_active_start related to leading edge of sync
*/
- h_blank = crtc_timing->h_total - crtc_timing->h_border_left -
- crtc_timing->h_addressable - crtc_timing->h_border_right;
+ h_blank = hw_crtc_timing.h_total - hw_crtc_timing.h_border_left -
+ hw_crtc_timing.h_addressable - hw_crtc_timing.h_border_right;
- h_back_porch = h_blank - crtc_timing->h_front_porch -
- crtc_timing->h_sync_width;
+ h_back_porch = h_blank - hw_crtc_timing.h_front_porch -
+ hw_crtc_timing.h_sync_width;
/* start at begining of left border */
- h_active_start = crtc_timing->h_sync_width + h_back_porch;
+ h_active_start = hw_crtc_timing.h_sync_width + h_back_porch;
- v_active_start = crtc_timing->v_total - crtc_timing->v_border_top -
- crtc_timing->v_addressable - crtc_timing->v_border_bottom -
- crtc_timing->v_front_porch;
+ v_active_start = hw_crtc_timing.v_total - hw_crtc_timing.v_border_top -
+ hw_crtc_timing.v_addressable - hw_crtc_timing.v_border_bottom -
+ hw_crtc_timing.v_front_porch;
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
@@ -486,21 +495,21 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
if (REG(DP_MSA_TIMING_PARAM3))
REG_SET_4(DP_MSA_TIMING_PARAM3, 0,
DP_MSA_HSYNCWIDTH,
- crtc_timing->h_sync_width,
+ hw_crtc_timing.h_sync_width,
DP_MSA_HSYNCPOLARITY,
- !crtc_timing->flags.HSYNC_POSITIVE_POLARITY,
+ !hw_crtc_timing.flags.HSYNC_POSITIVE_POLARITY,
DP_MSA_VSYNCWIDTH,
- crtc_timing->v_sync_width,
+ hw_crtc_timing.v_sync_width,
DP_MSA_VSYNCPOLARITY,
- !crtc_timing->flags.VSYNC_POSITIVE_POLARITY);
+ !hw_crtc_timing.flags.VSYNC_POSITIVE_POLARITY);
/* HWDITH include border or overscan */
if (REG(DP_MSA_TIMING_PARAM4))
REG_SET_2(DP_MSA_TIMING_PARAM4, 0,
- DP_MSA_HWIDTH, crtc_timing->h_border_left +
- crtc_timing->h_addressable + crtc_timing->h_border_right,
- DP_MSA_VHEIGHT, crtc_timing->v_border_top +
- crtc_timing->v_addressable + crtc_timing->v_border_bottom);
+ DP_MSA_HWIDTH, hw_crtc_timing.h_border_left +
+ hw_crtc_timing.h_addressable + hw_crtc_timing.h_border_right,
+ DP_MSA_VHEIGHT, hw_crtc_timing.v_border_top +
+ hw_crtc_timing.v_addressable + hw_crtc_timing.v_border_bottom);
#endif
}
#endif
@@ -662,7 +671,7 @@ static void dce110_stream_encoder_dvi_set_stream_attribute(
cntl.signal = is_dual_link ?
SIGNAL_TYPE_DVI_DUAL_LINK : SIGNAL_TYPE_DVI_SINGLE_LINK;
cntl.enable_dp_audio = false;
- cntl.pixel_clock = crtc_timing->pix_clk_khz;
+ cntl.pixel_clock = crtc_timing->pix_clk_100hz / 10;
cntl.lanes_number = (is_dual_link) ? LANE_COUNT_EIGHT : LANE_COUNT_FOUR;
if (enc110->base.bp->funcs->encoder_control(
@@ -686,7 +695,7 @@ static void dce110_stream_encoder_lvds_set_stream_attribute(
cntl.engine_id = enc110->base.id;
cntl.signal = SIGNAL_TYPE_LVDS;
cntl.enable_dp_audio = false;
- cntl.pixel_clock = crtc_timing->pix_clk_khz;
+ cntl.pixel_clock = crtc_timing->pix_clk_100hz / 10;
cntl.lanes_number = LANE_COUNT_FOUR;
if (enc110->base.bp->funcs->encoder_control(
@@ -1575,6 +1584,14 @@ static void setup_stereo_sync(
REG_UPDATE(DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, !enable);
}
+static void dig_connect_to_otg(
+ struct stream_encoder *enc,
+ int tg_inst)
+{
+ struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
+
+ REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst);
+}
static const struct stream_encoder_funcs dce110_str_enc_funcs = {
.dp_set_stream_attribute =
@@ -1609,7 +1626,7 @@ static const struct stream_encoder_funcs dce110_str_enc_funcs = {
.hdmi_audio_disable = dce110_se_hdmi_audio_disable,
.setup_stereo_sync = setup_stereo_sync,
.set_avmute = dce110_stream_encoder_set_avmute,
-
+ .dig_connect_to_otg = dig_connect_to_otg,
};
void dce110_stream_encoder_construct(
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h
index 6c28229c76eb..f9cdf2b5242c 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h
@@ -199,7 +199,8 @@
SE_SF(DP_SEC_CNTL, DP_SEC_ATP_ENABLE, mask_sh),\
SE_SF(DP_SEC_CNTL, DP_SEC_AIP_ENABLE, mask_sh),\
SE_SF(DP_SEC_CNTL, DP_SEC_ACM_ENABLE, mask_sh),\
- SE_SF(AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, mask_sh)
+ SE_SF(AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND, mask_sh),\
+ SE_SF(DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh)
#define SE_COMMON_MASK_SH_LIST_DCE_COMMON(mask_sh)\
SE_COMMON_MASK_SH_LIST_DCE_COMMON_BASE(mask_sh)
@@ -284,7 +285,8 @@
SE_SF(DIG0_DIG_FE_CNTL, TMDS_PIXEL_ENCODING, mask_sh),\
SE_SF(DIG0_DIG_FE_CNTL, TMDS_COLOR_FORMAT, mask_sh),\
SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_SELECT, mask_sh),\
- SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh)
+ SE_SF(DIG0_DIG_FE_CNTL, DIG_STEREOSYNC_GATE_EN, mask_sh),\
+ SE_SF(DIG0_DIG_FE_CNTL, DIG_SOURCE_SELECT, mask_sh)
#define SE_COMMON_MASK_SH_LIST_SOC(mask_sh)\
SE_COMMON_MASK_SH_LIST_SOC_BASE(mask_sh)
@@ -494,6 +496,7 @@ struct dce_stream_encoder_shift {
uint8_t HDMI_DB_DISABLE;
uint8_t DP_VID_N_MUL;
uint8_t DP_VID_M_DOUBLE_VALUE_EN;
+ uint8_t DIG_SOURCE_SELECT;
};
struct dce_stream_encoder_mask {
@@ -624,6 +627,7 @@ struct dce_stream_encoder_mask {
uint32_t HDMI_DB_DISABLE;
uint32_t DP_VID_N_MUL;
uint32_t DP_VID_M_DOUBLE_VALUE_EN;
+ uint32_t DIG_SOURCE_SELECT;
};
struct dce110_stream_enc_registers {