summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/mediatek
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-08-05 19:50:06 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-08-05 19:50:06 -0700
commit8186749621ed6b8fc42644c399e8c755a2b6f630 (patch)
tree3a1db67415da013e5dd481367c77db21e491edfb /drivers/gpu/drm/mediatek
parente4a7b2dc35d9582c253cf5e6d6c3605aabc7284d (diff)
parentdc100bc8fae59aafd2ea2e1a1a43ef1f65f8a8bc (diff)
Merge tag 'drm-next-2020-08-06' of git://anongit.freedesktop.org/drm/drm
Pull drm updates from Dave Airlie: "New xilinx displayport driver, AMD support for two new GPUs (more header files), i915 initial support for RocketLake and some work on their DG1 (discrete chip). The core also grew some lockdep annotations to try and constrain what drivers do with dma-fences, and added some documentation on why the idea of indefinite fences doesn't work. The long list is below. I do have some fixes trees outstanding, but I'll follow up with those later. core: - add user def flag to cmd line modes - dma_fence_wait added might_sleep - dma-fence lockdep annotations - indefinite fences are bad documentation - gem CMA functions used in more drivers - struct mutex removal - more drm_ debug macro usage - set/drop master api fixes - fix for drm/mm hole size comparison - drm/mm remove invalid entry optimization - optimise drm/mm hole handling - VRR debugfs added - uncompressed AFBC modifier support - multiple display id blocks in EDID - multiple driver sg handling fixes - __drm_atomic_helper_crtc_reset in all drivers - managed vram helpers ttm: - ttm_mem_reg handling cleanup - remove bo offset field - drop CMA memtype flag - drop mappable flag xilinx: - New Xilinx ZynqMP DisplayPort Subsystem driver nouveau: - add CRC support - start using NVIDIA published class header files - convert all push buffer emission to new macros - Proper push buffer space management for EVO/NVD channels. - firmware loading fixes - 2MiB system memory pages support on Pascal and newer vkms: - larger cursor support i915: - Rocketlake platform enablement - Early DG1 enablement - Numerous GEM refactorings - DP MST fixes - FBC, PSR, Cursor, Color, Gamma fixes - TGL, RKL, EHL workaround updates - TGL 8K display support fixes - SDVO/HDMI/DVI fixes amdgpu: - Initial support for Sienna Cichlid GPU - Initial support for Navy Flounder GPU - SI UVD/VCE support - expose rotation property - Add support for unique id on Arcturus - Enable runtime PM on vega10 boards that support BACO - Skip BAR resizing if the bios already did id - Major swSMU code cleanup - Fixes for DCN bandwidth calculations amdkfd: - Track SDMA usage per process - SMI events interface radeon: - Default to on chip GART for AGP boards on all arches - Runtime PM reference count fixes msm: - headers regenerated causing churn - a650/a640 display and GPU enablement - dpu dither support for 6bpc panels - dpu cursor fix - dsi/mdp5 enablement for sdm630/sdm636/sdm66 tegra: - video capture prep support - reflection support mediatek: - convert mtk_dsi to bridge API meson: - FBC support sun4i: - iommu support rockchip: - register locking fix - per-pixel alpha support PX30 VOP mgag200: - ported to simple and shmem helpers - device init cleanups - use managed pci functions - dropped hw cursor support ast: - use managed pci functions - use managed VRAM helpers - rework cursor support malidp: - dev_groups support hibmc: - refactor hibmc_drv_vdac: vc4: - create TXP CRTC imx: - error path fixes and cleanups etnaviv: - clock handling and error handling cleanups - use pin_user_pages" * tag 'drm-next-2020-08-06' of git://anongit.freedesktop.org/drm/drm: (1747 commits) drm/msm: use kthread_create_worker instead of kthread_run drm/msm/mdp5: Add MDP5 configuration for SDM636/660 drm/msm/dsi: Add DSI configuration for SDM660 drm/msm/mdp5: Add MDP5 configuration for SDM630 drm/msm/dsi: Add phy configuration for SDM630/636/660 drm/msm/a6xx: add A640/A650 hwcg drm/msm/a6xx: hwcg tables in gpulist drm/msm/dpu: add SM8250 to hw catalog drm/msm/dpu: add SM8150 to hw catalog drm/msm/dpu: intf timing path for displayport drm/msm/dpu: set missing flush bits for INTF_2 and INTF_3 drm/msm/dpu: don't use INTF_INPUT_CTRL feature on sdm845 drm/msm/dpu: move some sspp caps to dpu_caps drm/msm/dpu: update UBWC config for sm8150 and sm8250 drm/msm/dpu: use right setup_blend_config for sm8150 and sm8250 drm/msm/a6xx: set ubwc config for A640 and A650 drm/msm/adreno: un-open-code some packets drm/msm: sync generated headers drm/msm/a6xx: add build_bw_table for A640/A650 drm/msm/a6xx: fix crashstate capture for A650 ...
Diffstat (limited to 'drivers/gpu/drm/mediatek')
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_crtc.c20
-rw-r--r--drivers/gpu/drm/mediatek/mtk_drm_gem.c2
-rw-r--r--drivers/gpu/drm/mediatek/mtk_dsi.c269
-rw-r--r--drivers/gpu/drm/mediatek/mtk_hdmi.c2
4 files changed, 94 insertions, 199 deletions
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
index e6e134ae9c32..3fc5511330b9 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_crtc.c
@@ -113,19 +113,15 @@ static void mtk_drm_crtc_reset(struct drm_crtc *crtc)
{
struct mtk_crtc_state *state;
- if (crtc->state) {
+ if (crtc->state)
__drm_atomic_helper_crtc_destroy_state(crtc->state);
- state = to_mtk_crtc_state(crtc->state);
- memset(state, 0, sizeof(*state));
- } else {
- state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state)
- return;
- crtc->state = &state->base;
- }
+ kfree(to_mtk_crtc_state(crtc->state));
+ crtc->state = NULL;
- state->base.crtc = crtc;
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (state)
+ __drm_atomic_helper_crtc_reset(crtc, &state->base);
}
static struct drm_crtc_state *mtk_drm_crtc_duplicate_state(struct drm_crtc *crtc)
@@ -165,7 +161,7 @@ static void mtk_drm_crtc_mode_set_nofb(struct drm_crtc *crtc)
state->pending_width = crtc->mode.hdisplay;
state->pending_height = crtc->mode.vdisplay;
- state->pending_vrefresh = crtc->mode.vrefresh;
+ state->pending_vrefresh = drm_mode_vrefresh(&crtc->mode);
wmb(); /* Make sure the above parameters are set before update */
state->pending_config = true;
}
@@ -261,7 +257,7 @@ static int mtk_crtc_ddp_hw_init(struct mtk_drm_crtc *mtk_crtc)
width = crtc->state->adjusted_mode.hdisplay;
height = crtc->state->adjusted_mode.vdisplay;
- vrefresh = crtc->state->adjusted_mode.vrefresh;
+ vrefresh = drm_mode_vrefresh(&crtc->state->adjusted_mode);
drm_for_each_encoder(encoder, crtc->dev) {
if (encoder->crtc != crtc)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_gem.c b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
index f8fd8b98c30e..6190cc3b7b0d 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_gem.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_gem.c
@@ -117,7 +117,7 @@ int mtk_drm_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev,
goto err_handle_create;
/* drop reference from allocate - handle holds it now. */
- drm_gem_object_put_unlocked(&mtk_gem->base);
+ drm_gem_object_put(&mtk_gem->base);
return 0;
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 02ac55c13a80..16fd99dcdacf 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -17,6 +17,7 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_panel.h>
@@ -181,9 +182,9 @@ struct mtk_dsi {
struct device *dev;
struct mipi_dsi_host host;
struct drm_encoder encoder;
- struct drm_connector conn;
- struct drm_panel *panel;
- struct drm_bridge *bridge;
+ struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
+ struct drm_connector *connector;
struct phy *phy;
void __iomem *regs;
@@ -206,14 +207,9 @@ struct mtk_dsi {
const struct mtk_dsi_driver_data *driver_data;
};
-static inline struct mtk_dsi *encoder_to_dsi(struct drm_encoder *e)
-{
- return container_of(e, struct mtk_dsi, encoder);
-}
-
-static inline struct mtk_dsi *connector_to_dsi(struct drm_connector *c)
+static inline struct mtk_dsi *bridge_to_dsi(struct drm_bridge *b)
{
- return container_of(c, struct mtk_dsi, conn);
+ return container_of(b, struct mtk_dsi, bridge);
}
static inline struct mtk_dsi *host_to_dsi(struct mipi_dsi_host *h)
@@ -678,16 +674,7 @@ static int mtk_dsi_poweron(struct mtk_dsi *dsi)
mtk_dsi_lane0_ulp_mode_leave(dsi);
mtk_dsi_clk_hs_mode(dsi, 0);
- if (dsi->panel) {
- if (drm_panel_prepare(dsi->panel)) {
- DRM_ERROR("failed to prepare the panel\n");
- goto err_disable_digital_clk;
- }
- }
-
return 0;
-err_disable_digital_clk:
- clk_disable_unprepare(dsi->digital_clk);
err_disable_engine_clk:
clk_disable_unprepare(dsi->engine_clk);
err_phy_power_off:
@@ -714,15 +701,7 @@ static void mtk_dsi_poweroff(struct mtk_dsi *dsi)
*/
mtk_dsi_stop(dsi);
- if (!mtk_dsi_switch_to_cmd_mode(dsi, VM_DONE_INT_FLAG, 500)) {
- if (dsi->panel) {
- if (drm_panel_unprepare(dsi->panel)) {
- DRM_ERROR("failed to unprepare the panel\n");
- return;
- }
- }
- }
-
+ mtk_dsi_switch_to_cmd_mode(dsi, VM_DONE_INT_FLAG, 500);
mtk_dsi_reset_engine(dsi);
mtk_dsi_lane0_ulp_mode_enter(dsi);
mtk_dsi_clk_ulp_mode_enter(dsi);
@@ -753,19 +732,7 @@ static void mtk_output_dsi_enable(struct mtk_dsi *dsi)
mtk_dsi_start(dsi);
- if (dsi->panel) {
- if (drm_panel_enable(dsi->panel)) {
- DRM_ERROR("failed to enable the panel\n");
- goto err_dsi_power_off;
- }
- }
-
dsi->enabled = true;
-
- return;
-err_dsi_power_off:
- mtk_dsi_stop(dsi);
- mtk_dsi_poweroff(dsi);
}
static void mtk_output_dsi_disable(struct mtk_dsi *dsi)
@@ -773,155 +740,51 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi)
if (!dsi->enabled)
return;
- if (dsi->panel) {
- if (drm_panel_disable(dsi->panel)) {
- DRM_ERROR("failed to disable the panel\n");
- return;
- }
- }
-
mtk_dsi_poweroff(dsi);
dsi->enabled = false;
}
-static bool mtk_dsi_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+static int mtk_dsi_bridge_attach(struct drm_bridge *bridge,
+ enum drm_bridge_attach_flags flags)
{
- return true;
+ struct mtk_dsi *dsi = bridge_to_dsi(bridge);
+
+ /* Attach the panel or bridge to the dsi bridge */
+ return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
+ &dsi->bridge, flags);
}
-static void mtk_dsi_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted)
+static void mtk_dsi_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted)
{
- struct mtk_dsi *dsi = encoder_to_dsi(encoder);
+ struct mtk_dsi *dsi = bridge_to_dsi(bridge);
drm_display_mode_to_videomode(adjusted, &dsi->vm);
}
-static void mtk_dsi_encoder_disable(struct drm_encoder *encoder)
+static void mtk_dsi_bridge_disable(struct drm_bridge *bridge)
{
- struct mtk_dsi *dsi = encoder_to_dsi(encoder);
+ struct mtk_dsi *dsi = bridge_to_dsi(bridge);
mtk_output_dsi_disable(dsi);
}
-static void mtk_dsi_encoder_enable(struct drm_encoder *encoder)
+static void mtk_dsi_bridge_enable(struct drm_bridge *bridge)
{
- struct mtk_dsi *dsi = encoder_to_dsi(encoder);
+ struct mtk_dsi *dsi = bridge_to_dsi(bridge);
mtk_output_dsi_enable(dsi);
}
-static int mtk_dsi_connector_get_modes(struct drm_connector *connector)
-{
- struct mtk_dsi *dsi = connector_to_dsi(connector);
-
- return drm_panel_get_modes(dsi->panel, connector);
-}
-
-static const struct drm_encoder_helper_funcs mtk_dsi_encoder_helper_funcs = {
- .mode_fixup = mtk_dsi_encoder_mode_fixup,
- .mode_set = mtk_dsi_encoder_mode_set,
- .disable = mtk_dsi_encoder_disable,
- .enable = mtk_dsi_encoder_enable,
-};
-
-static const struct drm_connector_funcs mtk_dsi_connector_funcs = {
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = drm_connector_cleanup,
- .reset = drm_atomic_helper_connector_reset,
- .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
- .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+static const struct drm_bridge_funcs mtk_dsi_bridge_funcs = {
+ .attach = mtk_dsi_bridge_attach,
+ .disable = mtk_dsi_bridge_disable,
+ .enable = mtk_dsi_bridge_enable,
+ .mode_set = mtk_dsi_bridge_mode_set,
};
-static const struct drm_connector_helper_funcs
- mtk_dsi_connector_helper_funcs = {
- .get_modes = mtk_dsi_connector_get_modes,
-};
-
-static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
-{
- int ret;
-
- ret = drm_connector_init(drm, &dsi->conn, &mtk_dsi_connector_funcs,
- DRM_MODE_CONNECTOR_DSI);
- if (ret) {
- DRM_ERROR("Failed to connector init to drm\n");
- return ret;
- }
-
- drm_connector_helper_add(&dsi->conn, &mtk_dsi_connector_helper_funcs);
-
- dsi->conn.dpms = DRM_MODE_DPMS_OFF;
- drm_connector_attach_encoder(&dsi->conn, &dsi->encoder);
-
- if (dsi->panel) {
- ret = drm_panel_attach(dsi->panel, &dsi->conn);
- if (ret) {
- DRM_ERROR("Failed to attach panel to drm\n");
- goto err_connector_cleanup;
- }
- }
-
- return 0;
-
-err_connector_cleanup:
- drm_connector_cleanup(&dsi->conn);
- return ret;
-}
-
-static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi)
-{
- int ret;
-
- ret = drm_simple_encoder_init(drm, &dsi->encoder,
- DRM_MODE_ENCODER_DSI);
- if (ret) {
- DRM_ERROR("Failed to encoder init to drm\n");
- return ret;
- }
- drm_encoder_helper_add(&dsi->encoder, &mtk_dsi_encoder_helper_funcs);
-
- /*
- * Currently display data paths are statically assigned to a crtc each.
- * crtc 0 is OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0
- */
- dsi->encoder.possible_crtcs = 1;
-
- /* If there's a bridge, attach to it and let it create the connector */
- if (dsi->bridge) {
- ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL, 0);
- if (ret) {
- DRM_ERROR("Failed to attach bridge to drm\n");
- goto err_encoder_cleanup;
- }
- } else {
- /* Otherwise create our own connector and attach to a panel */
- ret = mtk_dsi_create_connector(drm, dsi);
- if (ret)
- goto err_encoder_cleanup;
- }
-
- return 0;
-
-err_encoder_cleanup:
- drm_encoder_cleanup(&dsi->encoder);
- return ret;
-}
-
-static void mtk_dsi_destroy_conn_enc(struct mtk_dsi *dsi)
-{
- drm_encoder_cleanup(&dsi->encoder);
- /* Skip connector cleanup if creation was delegated to the bridge */
- if (dsi->conn.dev)
- drm_connector_cleanup(&dsi->conn);
- if (dsi->panel)
- drm_panel_detach(dsi->panel);
-}
-
static void mtk_dsi_ddp_start(struct mtk_ddp_comp *comp)
{
struct mtk_dsi *dsi = container_of(comp, struct mtk_dsi, ddp_comp);
@@ -950,20 +813,6 @@ static int mtk_dsi_host_attach(struct mipi_dsi_host *host,
dsi->format = device->format;
dsi->mode_flags = device->mode_flags;
- if (dsi->conn.dev)
- drm_helper_hpd_irq_event(dsi->conn.dev);
-
- return 0;
-}
-
-static int mtk_dsi_host_detach(struct mipi_dsi_host *host,
- struct mipi_dsi_device *device)
-{
- struct mtk_dsi *dsi = host_to_dsi(host);
-
- if (dsi->conn.dev)
- drm_helper_hpd_irq_event(dsi->conn.dev);
-
return 0;
}
@@ -1107,10 +956,46 @@ static ssize_t mtk_dsi_host_transfer(struct mipi_dsi_host *host,
static const struct mipi_dsi_host_ops mtk_dsi_ops = {
.attach = mtk_dsi_host_attach,
- .detach = mtk_dsi_host_detach,
.transfer = mtk_dsi_host_transfer,
};
+static int mtk_dsi_encoder_init(struct drm_device *drm, struct mtk_dsi *dsi)
+{
+ int ret;
+
+ ret = drm_simple_encoder_init(drm, &dsi->encoder,
+ DRM_MODE_ENCODER_DSI);
+ if (ret) {
+ DRM_ERROR("Failed to encoder init to drm\n");
+ return ret;
+ }
+
+ /*
+ * Currently display data paths are statically assigned to a crtc each.
+ * crtc 0 is OVL0 -> COLOR0 -> AAL -> OD -> RDMA0 -> UFOE -> DSI0
+ */
+ dsi->encoder.possible_crtcs = 1;
+
+ ret = drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL,
+ DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+ if (ret)
+ goto err_cleanup_encoder;
+
+ dsi->connector = drm_bridge_connector_init(drm, &dsi->encoder);
+ if (IS_ERR(dsi->connector)) {
+ DRM_ERROR("Unable to create bridge connector\n");
+ ret = PTR_ERR(dsi->connector);
+ goto err_cleanup_encoder;
+ }
+ drm_connector_attach_encoder(dsi->connector, &dsi->encoder);
+
+ return 0;
+
+err_cleanup_encoder:
+ drm_encoder_cleanup(&dsi->encoder);
+ return ret;
+}
+
static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
{
int ret;
@@ -1124,11 +1009,9 @@ static int mtk_dsi_bind(struct device *dev, struct device *master, void *data)
return ret;
}
- ret = mtk_dsi_create_conn_enc(drm, dsi);
- if (ret) {
- DRM_ERROR("Encoder create failed with %d\n", ret);
+ ret = mtk_dsi_encoder_init(drm, dsi);
+ if (ret)
goto err_unregister;
- }
return 0;
@@ -1143,7 +1026,7 @@ static void mtk_dsi_unbind(struct device *dev, struct device *master,
struct drm_device *drm = data;
struct mtk_dsi *dsi = dev_get_drvdata(dev);
- mtk_dsi_destroy_conn_enc(dsi);
+ drm_encoder_cleanup(&dsi->encoder);
mtk_ddp_comp_unregister(drm, &dsi->ddp_comp);
}
@@ -1156,6 +1039,7 @@ static int mtk_dsi_probe(struct platform_device *pdev)
{
struct mtk_dsi *dsi;
struct device *dev = &pdev->dev;
+ struct drm_panel *panel;
struct resource *regs;
int irq_num;
int comp_id;
@@ -1174,10 +1058,18 @@ static int mtk_dsi_probe(struct platform_device *pdev)
}
ret = drm_of_find_panel_or_bridge(dev->of_node, 0, 0,
- &dsi->panel, &dsi->bridge);
+ &panel, &dsi->next_bridge);
if (ret)
goto err_unregister_host;
+ if (panel) {
+ dsi->next_bridge = devm_drm_panel_bridge_add(dev, panel);
+ if (IS_ERR(dsi->next_bridge)) {
+ ret = PTR_ERR(dsi->next_bridge);
+ goto err_unregister_host;
+ }
+ }
+
dsi->driver_data = of_device_get_match_data(dev);
dsi->engine_clk = devm_clk_get(dev, "engine");
@@ -1253,6 +1145,12 @@ static int mtk_dsi_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dsi);
+ dsi->bridge.funcs = &mtk_dsi_bridge_funcs;
+ dsi->bridge.of_node = dev->of_node;
+ dsi->bridge.type = DRM_MODE_CONNECTOR_DSI;
+
+ drm_bridge_add(&dsi->bridge);
+
ret = component_add(&pdev->dev, &mtk_dsi_component_ops);
if (ret) {
dev_err(&pdev->dev, "failed to add component: %d\n", ret);
@@ -1271,6 +1169,7 @@ static int mtk_dsi_remove(struct platform_device *pdev)
struct mtk_dsi *dsi = platform_get_drvdata(pdev);
mtk_output_dsi_disable(dsi);
+ drm_bridge_remove(&dsi->bridge);
component_del(&pdev->dev, &mtk_dsi_component_ops);
mipi_dsi_host_unregister(&dsi->host);
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 1eebe310470a..95591262ac36 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -1254,7 +1254,7 @@ static int mtk_hdmi_conn_mode_valid(struct drm_connector *conn,
struct drm_bridge *next_bridge;
dev_dbg(hdmi->dev, "xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
- mode->hdisplay, mode->vdisplay, mode->vrefresh,
+ mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode),
!!(mode->flags & DRM_MODE_FLAG_INTERLACE), mode->clock * 1000);
next_bridge = drm_bridge_get_next_bridge(&hdmi->bridge);