linux/drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012-15 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: AMD
  23 *
  24 */
  25
  26#include "dm_services.h"
  27
  28/*
  29 * Pre-requisites: headers required by header of this unit
  30 */
  31#include "include/i2caux_interface.h"
  32#include "../i2caux.h"
  33
  34/*
  35 * Header of this unit
  36 */
  37
  38#include "i2caux_dce80.h"
  39
  40/*
  41 * Post-requisites: headers required by this unit
  42 */
  43
  44#include "../engine.h"
  45#include "../i2c_engine.h"
  46#include "../i2c_sw_engine.h"
  47#include "i2c_sw_engine_dce80.h"
  48#include "../i2c_hw_engine.h"
  49#include "i2c_hw_engine_dce80.h"
  50#include "../i2c_generic_hw_engine.h"
  51#include "../aux_engine.h"
  52
  53
  54#include "../dce110/aux_engine_dce110.h"
  55#include "../dce110/i2caux_dce110.h"
  56
  57#include "dce/dce_8_0_d.h"
  58#include "dce/dce_8_0_sh_mask.h"
  59
  60
  61/* set register offset */
  62#define SR(reg_name)\
  63        .reg_name = mm ## reg_name
  64
  65/* set register offset with instance */
  66#define SRI(reg_name, block, id)\
  67        .reg_name = mm ## block ## id ## _ ## reg_name
  68
  69#define aux_regs(id)\
  70[id] = {\
  71        AUX_COMMON_REG_LIST(id), \
  72        .AUX_RESET_MASK = 0 \
  73}
  74
  75static const struct dce110_aux_registers dce80_aux_regs[] = {
  76                aux_regs(0),
  77                aux_regs(1),
  78                aux_regs(2),
  79                aux_regs(3),
  80                aux_regs(4),
  81                aux_regs(5)
  82};
  83
  84/*
  85 * This unit
  86 */
  87
  88#define FROM_I2C_AUX(ptr) \
  89        container_of((ptr), struct i2caux_dce80, base)
  90
  91static void destruct(
  92        struct i2caux_dce80 *i2caux_dce80)
  93{
  94        dal_i2caux_destruct(&i2caux_dce80->base);
  95}
  96
  97static void destroy(
  98        struct i2caux **i2c_engine)
  99{
 100        struct i2caux_dce80 *i2caux_dce80 = FROM_I2C_AUX(*i2c_engine);
 101
 102        destruct(i2caux_dce80);
 103
 104        kfree(i2caux_dce80);
 105
 106        *i2c_engine = NULL;
 107}
 108
 109static struct i2c_engine *acquire_i2c_hw_engine(
 110        struct i2caux *i2caux,
 111        struct ddc *ddc)
 112{
 113        struct i2caux_dce80 *i2caux_dce80 = FROM_I2C_AUX(i2caux);
 114
 115        struct i2c_engine *engine = NULL;
 116        bool non_generic;
 117
 118        if (!ddc)
 119                return NULL;
 120
 121        if (ddc->hw_info.hw_supported) {
 122                enum gpio_ddc_line line = dal_ddc_get_line(ddc);
 123
 124                if (line < GPIO_DDC_LINE_COUNT) {
 125                        non_generic = true;
 126                        engine = i2caux->i2c_hw_engines[line];
 127                }
 128        }
 129
 130        if (!engine) {
 131                non_generic = false;
 132                engine = i2caux->i2c_generic_hw_engine;
 133        }
 134
 135        if (!engine)
 136                return NULL;
 137
 138        if (non_generic) {
 139                if (!i2caux_dce80->i2c_hw_buffer_in_use &&
 140                        engine->base.funcs->acquire(&engine->base, ddc)) {
 141                        i2caux_dce80->i2c_hw_buffer_in_use = true;
 142                        return engine;
 143                }
 144        } else {
 145                if (engine->base.funcs->acquire(&engine->base, ddc))
 146                        return engine;
 147        }
 148
 149        return NULL;
 150}
 151
 152static void release_engine(
 153        struct i2caux *i2caux,
 154        struct engine *engine)
 155{
 156        if (engine->funcs->get_engine_type(engine) ==
 157                I2CAUX_ENGINE_TYPE_I2C_DDC_HW)
 158                FROM_I2C_AUX(i2caux)->i2c_hw_buffer_in_use = false;
 159
 160        dal_i2caux_release_engine(i2caux, engine);
 161}
 162
 163static const enum gpio_ddc_line hw_ddc_lines[] = {
 164        GPIO_DDC_LINE_DDC1,
 165        GPIO_DDC_LINE_DDC2,
 166        GPIO_DDC_LINE_DDC3,
 167        GPIO_DDC_LINE_DDC4,
 168        GPIO_DDC_LINE_DDC5,
 169        GPIO_DDC_LINE_DDC6,
 170        GPIO_DDC_LINE_DDC_VGA
 171};
 172
 173static const enum gpio_ddc_line hw_aux_lines[] = {
 174        GPIO_DDC_LINE_DDC1,
 175        GPIO_DDC_LINE_DDC2,
 176        GPIO_DDC_LINE_DDC3,
 177        GPIO_DDC_LINE_DDC4,
 178        GPIO_DDC_LINE_DDC5,
 179        GPIO_DDC_LINE_DDC6
 180};
 181
 182static const struct i2caux_funcs i2caux_funcs = {
 183        .destroy = destroy,
 184        .acquire_i2c_hw_engine = acquire_i2c_hw_engine,
 185        .release_engine = release_engine,
 186        .acquire_i2c_sw_engine = dal_i2caux_acquire_i2c_sw_engine,
 187        .acquire_aux_engine = dal_i2caux_acquire_aux_engine,
 188};
 189
 190static void construct(
 191        struct i2caux_dce80 *i2caux_dce80,
 192        struct dc_context *ctx)
 193{
 194        /* Entire family have I2C engine reference clock frequency
 195         * changed from XTALIN (27) to XTALIN/2 (13.5) */
 196
 197        struct i2caux *base = &i2caux_dce80->base;
 198
 199        uint32_t reference_frequency =
 200                dal_i2caux_get_reference_clock(ctx->dc_bios) >> 1;
 201
 202        /*bool use_i2c_sw_engine = dal_adapter_service_is_feature_supported(as,
 203                FEATURE_RESTORE_USAGE_I2C_SW_ENGINE);*/
 204
 205        /* Use SWI2C for dce8 currently, sicne we have bug with hwi2c */
 206        bool use_i2c_sw_engine = true;
 207
 208        uint32_t i;
 209
 210        dal_i2caux_construct(base, ctx);
 211
 212        i2caux_dce80->base.funcs = &i2caux_funcs;
 213        i2caux_dce80->i2c_hw_buffer_in_use = false;
 214
 215        /* Create I2C HW engines (HW + SW pairs)
 216         * for all lines which has assisted HW DDC
 217         * 'i' (loop counter) used as DDC/AUX engine_id */
 218
 219        i = 0;
 220
 221        do {
 222                enum gpio_ddc_line line_id = hw_ddc_lines[i];
 223
 224                struct i2c_hw_engine_dce80_create_arg hw_arg;
 225
 226                if (use_i2c_sw_engine) {
 227                        struct i2c_sw_engine_dce80_create_arg sw_arg;
 228
 229                        sw_arg.engine_id = i;
 230                        sw_arg.default_speed = base->default_i2c_sw_speed;
 231                        sw_arg.ctx = ctx;
 232                        base->i2c_sw_engines[line_id] =
 233                                dal_i2c_sw_engine_dce80_create(&sw_arg);
 234                }
 235
 236                hw_arg.engine_id = i;
 237                hw_arg.reference_frequency = reference_frequency;
 238                hw_arg.default_speed = base->default_i2c_hw_speed;
 239                hw_arg.ctx = ctx;
 240
 241                base->i2c_hw_engines[line_id] =
 242                        dal_i2c_hw_engine_dce80_create(&hw_arg);
 243
 244                ++i;
 245        } while (i < ARRAY_SIZE(hw_ddc_lines));
 246
 247        /* Create AUX engines for all lines which has assisted HW AUX
 248         * 'i' (loop counter) used as DDC/AUX engine_id */
 249
 250        i = 0;
 251
 252        do {
 253                enum gpio_ddc_line line_id = hw_aux_lines[i];
 254
 255                struct aux_engine_dce110_init_data arg;
 256
 257                arg.engine_id = i;
 258                arg.timeout_period = base->aux_timeout_period;
 259                arg.ctx = ctx;
 260                arg.regs = &dce80_aux_regs[i];
 261
 262                base->aux_engines[line_id] =
 263                        dal_aux_engine_dce110_create(&arg);
 264
 265                ++i;
 266        } while (i < ARRAY_SIZE(hw_aux_lines));
 267
 268        /* TODO Generic I2C SW and HW */
 269}
 270
 271struct i2caux *dal_i2caux_dce80_create(
 272        struct dc_context *ctx)
 273{
 274        struct i2caux_dce80 *i2caux_dce80 =
 275                kzalloc(sizeof(struct i2caux_dce80), GFP_KERNEL);
 276
 277        if (!i2caux_dce80) {
 278                BREAK_TO_DEBUGGER();
 279                return NULL;
 280        }
 281
 282        construct(i2caux_dce80, ctx);
 283        return &i2caux_dce80->base;
 284}
 285