Skip to content

Commit

Permalink
drm/radeon/kms: unify i2c handling
Browse files Browse the repository at this point in the history
Previously we added i2c buses as needed when enumerating connectors
power management, etc.  This only exposed the actual buses used and
could have lead to the same buse getting created more than once if
one buses was used for more than one purpose.  This patch sets up
all i2c buses on the card in one place and users of the buses just
point back to the one instance.

Signed-off-by: Alex Deucher <alexdeucher@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
  • Loading branch information
Alex Deucher authored and Dave Airlie committed Aug 10, 2010
1 parent 1729dd3 commit f376b94
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 32 deletions.
2 changes: 2 additions & 0 deletions drivers/gpu/drm/radeon/radeon.h
Original file line number Diff line number Diff line change
Expand Up @@ -1100,6 +1100,8 @@ struct radeon_device {
struct notifier_block acpi_nb;
/* only one userspace can use Hyperz features at a time */
struct drm_file *hyperz_filp;
/* i2c buses */
struct radeon_i2c_chan *i2c_bus[RADEON_MAX_I2C_BUS];
};

int radeon_device_init(struct radeon_device *rdev,
Expand Down
67 changes: 64 additions & 3 deletions drivers/gpu/drm/radeon/radeon_atombios.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev

i2c.i2c_id = gpio->sucI2cId.ucAccess;

i2c.valid = true;
if (i2c.mask_clk_reg)
i2c.valid = true;
break;
}
}
Expand All @@ -123,6 +124,66 @@ static inline struct radeon_i2c_bus_rec radeon_lookup_i2c_gpio(struct radeon_dev
return i2c;
}

void radeon_atombios_i2c_init(struct radeon_device *rdev)
{
struct atom_context *ctx = rdev->mode_info.atom_context;
ATOM_GPIO_I2C_ASSIGMENT *gpio;
struct radeon_i2c_bus_rec i2c;
int index = GetIndexIntoMasterTable(DATA, GPIO_I2C_Info);
struct _ATOM_GPIO_I2C_INFO *i2c_info;
uint16_t data_offset, size;
int i, num_indices;
char stmp[32];

memset(&i2c, 0, sizeof(struct radeon_i2c_bus_rec));

if (atom_parse_data_header(ctx, index, &size, NULL, NULL, &data_offset)) {
i2c_info = (struct _ATOM_GPIO_I2C_INFO *)(ctx->bios + data_offset);

num_indices = (size - sizeof(ATOM_COMMON_TABLE_HEADER)) /
sizeof(ATOM_GPIO_I2C_ASSIGMENT);

for (i = 0; i < num_indices; i++) {
gpio = &i2c_info->asGPIO_Info[i];
i2c.valid = false;
i2c.mask_clk_reg = le16_to_cpu(gpio->usClkMaskRegisterIndex) * 4;
i2c.mask_data_reg = le16_to_cpu(gpio->usDataMaskRegisterIndex) * 4;
i2c.en_clk_reg = le16_to_cpu(gpio->usClkEnRegisterIndex) * 4;
i2c.en_data_reg = le16_to_cpu(gpio->usDataEnRegisterIndex) * 4;
i2c.y_clk_reg = le16_to_cpu(gpio->usClkY_RegisterIndex) * 4;
i2c.y_data_reg = le16_to_cpu(gpio->usDataY_RegisterIndex) * 4;
i2c.a_clk_reg = le16_to_cpu(gpio->usClkA_RegisterIndex) * 4;
i2c.a_data_reg = le16_to_cpu(gpio->usDataA_RegisterIndex) * 4;
i2c.mask_clk_mask = (1 << gpio->ucClkMaskShift);
i2c.mask_data_mask = (1 << gpio->ucDataMaskShift);
i2c.en_clk_mask = (1 << gpio->ucClkEnShift);
i2c.en_data_mask = (1 << gpio->ucDataEnShift);
i2c.y_clk_mask = (1 << gpio->ucClkY_Shift);
i2c.y_data_mask = (1 << gpio->ucDataY_Shift);
i2c.a_clk_mask = (1 << gpio->ucClkA_Shift);
i2c.a_data_mask = (1 << gpio->ucDataA_Shift);

if (gpio->sucI2cId.sbfAccess.bfHW_Capable)
i2c.hw_capable = true;
else
i2c.hw_capable = false;

if (gpio->sucI2cId.ucAccess == 0xa0)
i2c.mm_i2c = true;
else
i2c.mm_i2c = false;

i2c.i2c_id = gpio->sucI2cId.ucAccess;

if (i2c.mask_clk_reg) {
i2c.valid = true;
sprintf(stmp, "0x%x", i2c.i2c_id);
rdev->i2c_bus[i] = radeon_i2c_create(rdev->ddev, &i2c, stmp);
}
}
}
}

static inline struct radeon_gpio_rec radeon_lookup_gpio(struct radeon_device *rdev,
u8 id)
{
Expand Down Expand Up @@ -1521,7 +1582,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
thermal_controller_names[power_info->info.ucOverdriveThermalController],
power_info->info.ucOverdriveControllerAddress >> 1);
i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine);
rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal");
rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
if (rdev->pm.i2c_bus) {
struct i2c_board_info info = { };
const char *name = thermal_controller_names[power_info->info.
Expand Down Expand Up @@ -1814,7 +1875,7 @@ void radeon_atombios_get_power_modes(struct radeon_device *rdev)
(controller->ucFanParameters &
ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine);
rdev->pm.i2c_bus = radeon_i2c_create(rdev->ddev, &i2c_bus, "Thermal");
rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
if (rdev->pm.i2c_bus) {
struct i2c_board_info info = { };
const char *name = pp_lib_thermal_controller_names[controller->ucType];
Expand Down
77 changes: 69 additions & 8 deletions drivers/gpu/drm/radeon/radeon_combios.c
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,17 @@ radeon_combios_get_hardcoded_edid(struct radeon_device *rdev)
return NULL;
}

/* standard i2c gpio lines */
#define RADEON_I2C_MONID_ID 0
#define RADEON_I2C_DVI_ID 1
#define RADEON_I2C_VGA_ID 2
#define RADEON_I2C_CRT2_ID 3
#define RADEON_I2C_MM_ID 4
/* custom defined gpio lines */
#define RADEON_I2C_LCD_ID 5 /* ddc for laptop panels */
#define RADEON_I2C_GPIO_ID 6 /* rs4xx gpio ddc */
#define RADEON_I2C_DVO_ID 7 /* i2c bus for dvo */

static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rdev,
int ddc_line)
{
Expand Down Expand Up @@ -599,7 +610,24 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
break;
}
i2c.mm_i2c = false;
i2c.i2c_id = 0;

switch (ddc_line) {
case RADEON_GPIO_MONID:
i2c.i2c_id = RADEON_I2C_MONID_ID;
break;
case RADEON_GPIO_DVI_DDC:
i2c.i2c_id = RADEON_I2C_DVI_ID;
break;
case RADEON_GPIO_VGA_DDC:
i2c.i2c_id = RADEON_I2C_VGA_ID;
break;
case RADEON_GPIO_CRT2_DDC:
i2c.i2c_id = RADEON_I2C_CRT2_ID;
break;
default:
i2c.i2c_id = 0xff;
break;
}
i2c.hpd = RADEON_HPD_NONE;

if (ddc_line)
Expand All @@ -610,6 +638,30 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
return i2c;
}

void radeon_combios_i2c_init(struct radeon_device *rdev)
{
struct drm_device *dev = rdev->ddev;
struct radeon_i2c_bus_rec i2c;

i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
rdev->i2c_bus[0] = radeon_i2c_create(dev, &i2c, "MONID");

i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
rdev->i2c_bus[1] = radeon_i2c_create(dev, &i2c, "DVI_DDC");

i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
rdev->i2c_bus[2] = radeon_i2c_create(dev, &i2c, "VGA_DDC");

i2c = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "CRT2_DDC");

i2c.valid = true;
i2c.hw_capable = true;
i2c.mm_i2c = true;
i2c.i2c_id = RADEON_I2C_MM_ID;
rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "MM_I2C");
}

bool radeon_combios_get_clock_info(struct drm_device *dev)
{
struct radeon_device *rdev = dev->dev_private;
Expand Down Expand Up @@ -1248,7 +1300,7 @@ bool radeon_legacy_get_ext_tmds_info_from_table(struct radeon_encoder *encoder,

/* default for macs */
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);

/* XXX some macs have duallink chips */
switch (rdev->mode_info.connector_table) {
Expand Down Expand Up @@ -1303,7 +1355,9 @@ bool radeon_legacy_get_ext_tmds_info_from_combios(struct radeon_encoder *encoder
i2c_bus.en_data_reg = RADEON_GPIOPAD_EN;
i2c_bus.y_clk_reg = RADEON_GPIOPAD_Y;
i2c_bus.y_data_reg = RADEON_GPIOPAD_Y;
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
i2c_bus.i2c_id = RADEON_I2C_DVO_ID;
radeon_i2c_add(rdev, &i2c_bus, "DVO");
tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
tmds->dvo_chip = DVO_SIL164;
tmds->slave_addr = 0x70 >> 1; /* 7 bit addressing */
break;
Expand All @@ -1321,29 +1375,30 @@ bool radeon_legacy_get_ext_tmds_info_from_combios(struct radeon_encoder *encoder
switch (gpio) {
case DDC_MONID:
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
break;
case DDC_DVI:
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_DVI_DDC);
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
break;
case DDC_VGA:
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_VGA_DDC);
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
break;
case DDC_CRT2:
/* R3xx+ chips don't have GPIO_CRT2_DDC gpio pad */
if (rdev->family >= CHIP_R300)
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_MONID);
else
i2c_bus = combios_setup_i2c_bus(rdev, RADEON_GPIO_CRT2_DDC);
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
break;
case DDC_LCD: /* MM i2c */
i2c_bus.valid = true;
i2c_bus.hw_capable = true;
i2c_bus.mm_i2c = true;
tmds->i2c_bus = radeon_i2c_create(dev, &i2c_bus, "DVO");
i2c_bus.i2c_id = RADEON_I2C_MM_ID;
tmds->i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
break;
default:
DRM_ERROR("Unsupported gpio %d\n", gpio);
Expand Down Expand Up @@ -1926,6 +1981,8 @@ static bool radeon_apply_legacy_quirks(struct drm_device *dev,
ddc_i2c->en_data_mask = 0x80;
ddc_i2c->y_clk_mask = (0x20 << 8);
ddc_i2c->y_data_mask = 0x80;
ddc_i2c->i2c_id = RADEON_I2C_GPIO_ID;
radeon_i2c_add(rdev, ddc_i2c, "GPIO_DDC");
}

/* R3xx+ chips don't have GPIO_CRT2_DDC gpio pad */
Expand Down Expand Up @@ -2318,6 +2375,8 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
RBIOS32(lcd_ddc_info + 3);
ddc_i2c.y_data_mask =
RBIOS32(lcd_ddc_info + 7);
ddc_i2c.i2c_id = RADEON_I2C_LCD_ID;
radeon_i2c_add(rdev, &ddc_i2c, "LCD");
break;
case DDC_GPIO:
ddc_i2c =
Expand All @@ -2339,6 +2398,8 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
RBIOS32(lcd_ddc_info + 3);
ddc_i2c.y_data_mask =
RBIOS32(lcd_ddc_info + 7);
ddc_i2c.i2c_id = RADEON_I2C_LCD_ID;
radeon_i2c_add(rdev, &ddc_i2c, "LCD");
break;
default:
ddc_i2c.valid = false;
Expand Down
31 changes: 10 additions & 21 deletions drivers/gpu/drm/radeon/radeon_connectors.c
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,6 @@ static void radeon_connector_destroy(struct drm_connector *connector)
{
struct radeon_connector *radeon_connector = to_radeon_connector(connector);

if (radeon_connector->ddc_bus)
radeon_i2c_destroy(radeon_connector->ddc_bus);
if (radeon_connector->edid)
kfree(radeon_connector->edid);
kfree(radeon_connector->con_priv);
Expand Down Expand Up @@ -955,8 +953,6 @@ static void radeon_dp_connector_destroy(struct drm_connector *connector)
struct radeon_connector *radeon_connector = to_radeon_connector(connector);
struct radeon_connector_atom_dig *radeon_dig_connector = radeon_connector->con_priv;

if (radeon_connector->ddc_bus)
radeon_i2c_destroy(radeon_connector->ddc_bus);
if (radeon_connector->edid)
kfree(radeon_connector->edid);
if (radeon_dig_connector->dp_i2c_bus)
Expand Down Expand Up @@ -1088,7 +1084,7 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
goto failed;
}
Expand All @@ -1104,7 +1100,7 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
goto failed;
}
Expand All @@ -1126,7 +1122,7 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
goto failed;
}
Expand Down Expand Up @@ -1156,7 +1152,7 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "HDMI");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
goto failed;
}
Expand Down Expand Up @@ -1187,10 +1183,7 @@ radeon_add_atom_connector(struct drm_device *dev,
radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
if (!radeon_dig_connector->dp_i2c_bus)
goto failed;
if (connector_type == DRM_MODE_CONNECTOR_eDP)
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "eDP");
else
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DP");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
goto failed;
}
Expand Down Expand Up @@ -1230,7 +1223,7 @@ radeon_add_atom_connector(struct drm_device *dev,
drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
goto failed;
}
Expand All @@ -1252,8 +1245,6 @@ radeon_add_atom_connector(struct drm_device *dev,
return;

failed:
if (radeon_connector->ddc_bus)
radeon_i2c_destroy(radeon_connector->ddc_bus);
drm_connector_cleanup(connector);
kfree(connector);
}
Expand Down Expand Up @@ -1300,7 +1291,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "VGA");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
goto failed;
}
Expand All @@ -1316,7 +1307,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
drm_connector_init(dev, &radeon_connector->base, &radeon_vga_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_vga_connector_helper_funcs);
if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
goto failed;
}
Expand All @@ -1332,7 +1323,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
drm_connector_init(dev, &radeon_connector->base, &radeon_dvi_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_dvi_connector_helper_funcs);
if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "DVI");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
goto failed;
}
Expand Down Expand Up @@ -1372,7 +1363,7 @@ radeon_add_legacy_connector(struct drm_device *dev,
drm_connector_init(dev, &radeon_connector->base, &radeon_lvds_connector_funcs, connector_type);
drm_connector_helper_add(&radeon_connector->base, &radeon_lvds_connector_helper_funcs);
if (i2c_bus->valid) {
radeon_connector->ddc_bus = radeon_i2c_create(dev, i2c_bus, "LVDS");
radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
if (!radeon_connector->ddc_bus)
goto failed;
}
Expand All @@ -1393,8 +1384,6 @@ radeon_add_legacy_connector(struct drm_device *dev,
return;

failed:
if (radeon_connector->ddc_bus)
radeon_i2c_destroy(radeon_connector->ddc_bus);
drm_connector_cleanup(connector);
kfree(connector);
}
Loading

0 comments on commit f376b94

Please sign in to comment.