172317eaaSNeil Armstrong // SPDX-License-Identifier: GPL-2.0-or-later
272317eaaSNeil Armstrong /*
372317eaaSNeil Armstrong  * Copyright (C) 2016 BayLibre, SAS
472317eaaSNeil Armstrong  * Author: Neil Armstrong <narmstrong@baylibre.com>
572317eaaSNeil Armstrong  * Copyright (C) 2015 Amlogic, Inc. All rights reserved.
672317eaaSNeil Armstrong  * Copyright (C) 2014 Endless Mobile
772317eaaSNeil Armstrong  *
872317eaaSNeil Armstrong  * Written by:
972317eaaSNeil Armstrong  *     Jasper St. Pierre <jstpierre@mecheye.net>
1072317eaaSNeil Armstrong  */
1172317eaaSNeil Armstrong 
1272317eaaSNeil Armstrong #include <linux/export.h>
1372317eaaSNeil Armstrong #include <linux/of_graph.h>
1472317eaaSNeil Armstrong 
1572317eaaSNeil Armstrong #include <drm/drm_atomic_helper.h>
16318ba02cSNeil Armstrong #include <drm/drm_bridge.h>
17318ba02cSNeil Armstrong #include <drm/drm_bridge_connector.h>
1872317eaaSNeil Armstrong #include <drm/drm_device.h>
1972317eaaSNeil Armstrong #include <drm/drm_edid.h>
2072317eaaSNeil Armstrong #include <drm/drm_probe_helper.h>
21318ba02cSNeil Armstrong #include <drm/drm_simple_kms_helper.h>
2272317eaaSNeil Armstrong 
2372317eaaSNeil Armstrong #include "meson_registers.h"
2472317eaaSNeil Armstrong #include "meson_vclk.h"
2572317eaaSNeil Armstrong #include "meson_encoder_cvbs.h"
2672317eaaSNeil Armstrong 
2772317eaaSNeil Armstrong /* HHI VDAC Registers */
2872317eaaSNeil Armstrong #define HHI_VDAC_CNTL0		0x2F4 /* 0xbd offset in data sheet */
2972317eaaSNeil Armstrong #define HHI_VDAC_CNTL0_G12A	0x2EC /* 0xbd offset in data sheet */
3072317eaaSNeil Armstrong #define HHI_VDAC_CNTL1		0x2F8 /* 0xbe offset in data sheet */
3172317eaaSNeil Armstrong #define HHI_VDAC_CNTL1_G12A	0x2F0 /* 0xbe offset in data sheet */
3272317eaaSNeil Armstrong 
3372317eaaSNeil Armstrong struct meson_encoder_cvbs {
3472317eaaSNeil Armstrong 	struct drm_encoder	encoder;
35318ba02cSNeil Armstrong 	struct drm_bridge	bridge;
36318ba02cSNeil Armstrong 	struct drm_bridge	*next_bridge;
3772317eaaSNeil Armstrong 	struct meson_drm	*priv;
3872317eaaSNeil Armstrong };
3972317eaaSNeil Armstrong 
40318ba02cSNeil Armstrong #define bridge_to_meson_encoder_cvbs(x) \
41318ba02cSNeil Armstrong 	container_of(x, struct meson_encoder_cvbs, bridge)
4272317eaaSNeil Armstrong 
4372317eaaSNeil Armstrong /* Supported Modes */
4472317eaaSNeil Armstrong 
4572317eaaSNeil Armstrong struct meson_cvbs_mode meson_cvbs_modes[MESON_CVBS_MODES_COUNT] = {
4672317eaaSNeil Armstrong 	{ /* PAL */
4772317eaaSNeil Armstrong 		.enci = &meson_cvbs_enci_pal,
4872317eaaSNeil Armstrong 		.mode = {
4972317eaaSNeil Armstrong 			DRM_MODE("720x576i", DRM_MODE_TYPE_DRIVER, 13500,
5072317eaaSNeil Armstrong 				 720, 732, 795, 864, 0, 576, 580, 586, 625, 0,
5172317eaaSNeil Armstrong 				 DRM_MODE_FLAG_INTERLACE),
5272317eaaSNeil Armstrong 			.picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3,
5372317eaaSNeil Armstrong 		},
5472317eaaSNeil Armstrong 	},
5572317eaaSNeil Armstrong 	{ /* NTSC */
5672317eaaSNeil Armstrong 		.enci = &meson_cvbs_enci_ntsc,
5772317eaaSNeil Armstrong 		.mode = {
5872317eaaSNeil Armstrong 			DRM_MODE("720x480i", DRM_MODE_TYPE_DRIVER, 13500,
5972317eaaSNeil Armstrong 				720, 739, 801, 858, 0, 480, 488, 494, 525, 0,
6072317eaaSNeil Armstrong 				DRM_MODE_FLAG_INTERLACE),
6172317eaaSNeil Armstrong 			.picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3,
6272317eaaSNeil Armstrong 		},
6372317eaaSNeil Armstrong 	},
6472317eaaSNeil Armstrong };
6572317eaaSNeil Armstrong 
6672317eaaSNeil Armstrong static const struct meson_cvbs_mode *
meson_cvbs_get_mode(const struct drm_display_mode * req_mode)6772317eaaSNeil Armstrong meson_cvbs_get_mode(const struct drm_display_mode *req_mode)
6872317eaaSNeil Armstrong {
6972317eaaSNeil Armstrong 	int i;
7072317eaaSNeil Armstrong 
7172317eaaSNeil Armstrong 	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
7272317eaaSNeil Armstrong 		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
7372317eaaSNeil Armstrong 
7472317eaaSNeil Armstrong 		if (drm_mode_match(req_mode, &meson_mode->mode,
7572317eaaSNeil Armstrong 				   DRM_MODE_MATCH_TIMINGS |
7672317eaaSNeil Armstrong 				   DRM_MODE_MATCH_CLOCK |
7772317eaaSNeil Armstrong 				   DRM_MODE_MATCH_FLAGS |
7872317eaaSNeil Armstrong 				   DRM_MODE_MATCH_3D_FLAGS))
7972317eaaSNeil Armstrong 			return meson_mode;
8072317eaaSNeil Armstrong 	}
8172317eaaSNeil Armstrong 
8272317eaaSNeil Armstrong 	return NULL;
8372317eaaSNeil Armstrong }
8472317eaaSNeil Armstrong 
meson_encoder_cvbs_attach(struct drm_bridge * bridge,enum drm_bridge_attach_flags flags)85318ba02cSNeil Armstrong static int meson_encoder_cvbs_attach(struct drm_bridge *bridge,
86318ba02cSNeil Armstrong 				     enum drm_bridge_attach_flags flags)
8772317eaaSNeil Armstrong {
88318ba02cSNeil Armstrong 	struct meson_encoder_cvbs *meson_encoder_cvbs =
89318ba02cSNeil Armstrong 					bridge_to_meson_encoder_cvbs(bridge);
90318ba02cSNeil Armstrong 
91318ba02cSNeil Armstrong 	return drm_bridge_attach(bridge->encoder, meson_encoder_cvbs->next_bridge,
92318ba02cSNeil Armstrong 				 &meson_encoder_cvbs->bridge, flags);
9372317eaaSNeil Armstrong }
9472317eaaSNeil Armstrong 
meson_encoder_cvbs_get_modes(struct drm_bridge * bridge,struct drm_connector * connector)95318ba02cSNeil Armstrong static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
96318ba02cSNeil Armstrong 					struct drm_connector *connector)
9772317eaaSNeil Armstrong {
98318ba02cSNeil Armstrong 	struct meson_encoder_cvbs *meson_encoder_cvbs =
99318ba02cSNeil Armstrong 					bridge_to_meson_encoder_cvbs(bridge);
100318ba02cSNeil Armstrong 	struct meson_drm *priv = meson_encoder_cvbs->priv;
10172317eaaSNeil Armstrong 	struct drm_display_mode *mode;
10272317eaaSNeil Armstrong 	int i;
10372317eaaSNeil Armstrong 
10472317eaaSNeil Armstrong 	for (i = 0; i < MESON_CVBS_MODES_COUNT; ++i) {
10572317eaaSNeil Armstrong 		struct meson_cvbs_mode *meson_mode = &meson_cvbs_modes[i];
10672317eaaSNeil Armstrong 
107318ba02cSNeil Armstrong 		mode = drm_mode_duplicate(priv->drm, &meson_mode->mode);
10872317eaaSNeil Armstrong 		if (!mode) {
109318ba02cSNeil Armstrong 			dev_err(priv->dev, "Failed to create a new display mode\n");
11072317eaaSNeil Armstrong 			return 0;
11172317eaaSNeil Armstrong 		}
11272317eaaSNeil Armstrong 
11372317eaaSNeil Armstrong 		drm_mode_probed_add(connector, mode);
11472317eaaSNeil Armstrong 	}
11572317eaaSNeil Armstrong 
11672317eaaSNeil Armstrong 	return i;
11772317eaaSNeil Armstrong }
11872317eaaSNeil Armstrong 
119*6c4e4d35SNathan Chancellor static enum drm_mode_status
meson_encoder_cvbs_mode_valid(struct drm_bridge * bridge,const struct drm_display_info * display_info,const struct drm_display_mode * mode)120*6c4e4d35SNathan Chancellor meson_encoder_cvbs_mode_valid(struct drm_bridge *bridge,
121318ba02cSNeil Armstrong 			      const struct drm_display_info *display_info,
122318ba02cSNeil Armstrong 			      const struct drm_display_mode *mode)
12372317eaaSNeil Armstrong {
124318ba02cSNeil Armstrong 	if (meson_cvbs_get_mode(mode))
12572317eaaSNeil Armstrong 		return MODE_OK;
126318ba02cSNeil Armstrong 
127318ba02cSNeil Armstrong 	return MODE_BAD;
12872317eaaSNeil Armstrong }
12972317eaaSNeil Armstrong 
meson_encoder_cvbs_atomic_check(struct drm_bridge * bridge,struct drm_bridge_state * bridge_state,struct drm_crtc_state * crtc_state,struct drm_connector_state * conn_state)130318ba02cSNeil Armstrong static int meson_encoder_cvbs_atomic_check(struct drm_bridge *bridge,
131318ba02cSNeil Armstrong 					struct drm_bridge_state *bridge_state,
13272317eaaSNeil Armstrong 					struct drm_crtc_state *crtc_state,
13372317eaaSNeil Armstrong 					struct drm_connector_state *conn_state)
13472317eaaSNeil Armstrong {
13572317eaaSNeil Armstrong 	if (meson_cvbs_get_mode(&crtc_state->mode))
13672317eaaSNeil Armstrong 		return 0;
13772317eaaSNeil Armstrong 
13872317eaaSNeil Armstrong 	return -EINVAL;
13972317eaaSNeil Armstrong }
14072317eaaSNeil Armstrong 
meson_encoder_cvbs_atomic_enable(struct drm_bridge * bridge,struct drm_bridge_state * bridge_state)141318ba02cSNeil Armstrong static void meson_encoder_cvbs_atomic_enable(struct drm_bridge *bridge,
142318ba02cSNeil Armstrong 					     struct drm_bridge_state *bridge_state)
14372317eaaSNeil Armstrong {
144318ba02cSNeil Armstrong 	struct meson_encoder_cvbs *encoder_cvbs = bridge_to_meson_encoder_cvbs(bridge);
145318ba02cSNeil Armstrong 	struct drm_atomic_state *state = bridge_state->base.state;
146318ba02cSNeil Armstrong 	struct meson_drm *priv = encoder_cvbs->priv;
147318ba02cSNeil Armstrong 	const struct meson_cvbs_mode *meson_mode;
148318ba02cSNeil Armstrong 	struct drm_connector_state *conn_state;
149318ba02cSNeil Armstrong 	struct drm_crtc_state *crtc_state;
150318ba02cSNeil Armstrong 	struct drm_connector *connector;
15172317eaaSNeil Armstrong 
152318ba02cSNeil Armstrong 	connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
153318ba02cSNeil Armstrong 	if (WARN_ON(!connector))
154318ba02cSNeil Armstrong 		return;
15572317eaaSNeil Armstrong 
156318ba02cSNeil Armstrong 	conn_state = drm_atomic_get_new_connector_state(state, connector);
157318ba02cSNeil Armstrong 	if (WARN_ON(!conn_state))
158318ba02cSNeil Armstrong 		return;
159318ba02cSNeil Armstrong 
160318ba02cSNeil Armstrong 	crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
161318ba02cSNeil Armstrong 	if (WARN_ON(!crtc_state))
162318ba02cSNeil Armstrong 		return;
163318ba02cSNeil Armstrong 
164318ba02cSNeil Armstrong 	meson_mode = meson_cvbs_get_mode(&crtc_state->adjusted_mode);
165318ba02cSNeil Armstrong 	if (WARN_ON(!meson_mode))
166318ba02cSNeil Armstrong 		return;
167318ba02cSNeil Armstrong 
168318ba02cSNeil Armstrong 	meson_venci_cvbs_mode_set(priv, meson_mode->enci);
169318ba02cSNeil Armstrong 
170318ba02cSNeil Armstrong 	/* Setup 27MHz vclk2 for ENCI and VDAC */
171318ba02cSNeil Armstrong 	meson_vclk_setup(priv, MESON_VCLK_TARGET_CVBS,
172318ba02cSNeil Armstrong 			 MESON_VCLK_CVBS, MESON_VCLK_CVBS,
173318ba02cSNeil Armstrong 			 MESON_VCLK_CVBS, MESON_VCLK_CVBS,
174318ba02cSNeil Armstrong 			 true);
17572317eaaSNeil Armstrong 
17672317eaaSNeil Armstrong 	/* VDAC0 source is not from ATV */
17772317eaaSNeil Armstrong 	writel_bits_relaxed(VENC_VDAC_SEL_ATV_DMD, 0,
17872317eaaSNeil Armstrong 			    priv->io_base + _REG(VENC_VDAC_DACSEL0));
17972317eaaSNeil Armstrong 
18072317eaaSNeil Armstrong 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXBB)) {
18172317eaaSNeil Armstrong 		regmap_write(priv->hhi, HHI_VDAC_CNTL0, 1);
18272317eaaSNeil Armstrong 		regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
18372317eaaSNeil Armstrong 	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXM) ||
18472317eaaSNeil Armstrong 		 meson_vpu_is_compatible(priv, VPU_COMPATIBLE_GXL)) {
18572317eaaSNeil Armstrong 		regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0xf0001);
18672317eaaSNeil Armstrong 		regmap_write(priv->hhi, HHI_VDAC_CNTL1, 0);
18772317eaaSNeil Armstrong 	} else if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
18872317eaaSNeil Armstrong 		regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0x906001);
18972317eaaSNeil Armstrong 		regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
19072317eaaSNeil Armstrong 	}
19172317eaaSNeil Armstrong }
19272317eaaSNeil Armstrong 
meson_encoder_cvbs_atomic_disable(struct drm_bridge * bridge,struct drm_bridge_state * bridge_state)193318ba02cSNeil Armstrong static void meson_encoder_cvbs_atomic_disable(struct drm_bridge *bridge,
194318ba02cSNeil Armstrong 					      struct drm_bridge_state *bridge_state)
19572317eaaSNeil Armstrong {
19672317eaaSNeil Armstrong 	struct meson_encoder_cvbs *meson_encoder_cvbs =
197318ba02cSNeil Armstrong 					bridge_to_meson_encoder_cvbs(bridge);
19872317eaaSNeil Armstrong 	struct meson_drm *priv = meson_encoder_cvbs->priv;
19972317eaaSNeil Armstrong 
200318ba02cSNeil Armstrong 	/* Disable CVBS VDAC */
201318ba02cSNeil Armstrong 	if (meson_vpu_is_compatible(priv, VPU_COMPATIBLE_G12A)) {
202318ba02cSNeil Armstrong 		regmap_write(priv->hhi, HHI_VDAC_CNTL0_G12A, 0);
203318ba02cSNeil Armstrong 		regmap_write(priv->hhi, HHI_VDAC_CNTL1_G12A, 0);
204318ba02cSNeil Armstrong 	} else {
205318ba02cSNeil Armstrong 		regmap_write(priv->hhi, HHI_VDAC_CNTL0, 0);
206318ba02cSNeil Armstrong 		regmap_write(priv->hhi, HHI_VDAC_CNTL1, 8);
20772317eaaSNeil Armstrong 	}
20872317eaaSNeil Armstrong }
20972317eaaSNeil Armstrong 
210318ba02cSNeil Armstrong static const struct drm_bridge_funcs meson_encoder_cvbs_bridge_funcs = {
211318ba02cSNeil Armstrong 	.attach = meson_encoder_cvbs_attach,
212318ba02cSNeil Armstrong 	.mode_valid = meson_encoder_cvbs_mode_valid,
213318ba02cSNeil Armstrong 	.get_modes = meson_encoder_cvbs_get_modes,
214318ba02cSNeil Armstrong 	.atomic_enable = meson_encoder_cvbs_atomic_enable,
215318ba02cSNeil Armstrong 	.atomic_disable = meson_encoder_cvbs_atomic_disable,
216318ba02cSNeil Armstrong 	.atomic_check = meson_encoder_cvbs_atomic_check,
217318ba02cSNeil Armstrong 	.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
218318ba02cSNeil Armstrong 	.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
219318ba02cSNeil Armstrong 	.atomic_reset = drm_atomic_helper_bridge_reset,
22072317eaaSNeil Armstrong };
22172317eaaSNeil Armstrong 
meson_encoder_cvbs_init(struct meson_drm * priv)22272317eaaSNeil Armstrong int meson_encoder_cvbs_init(struct meson_drm *priv)
22372317eaaSNeil Armstrong {
22472317eaaSNeil Armstrong 	struct drm_device *drm = priv->drm;
22572317eaaSNeil Armstrong 	struct meson_encoder_cvbs *meson_encoder_cvbs;
22672317eaaSNeil Armstrong 	struct drm_connector *connector;
227318ba02cSNeil Armstrong 	struct device_node *remote;
22872317eaaSNeil Armstrong 	int ret;
22972317eaaSNeil Armstrong 
230318ba02cSNeil Armstrong 	meson_encoder_cvbs = devm_kzalloc(priv->dev, sizeof(*meson_encoder_cvbs), GFP_KERNEL);
231318ba02cSNeil Armstrong 	if (!meson_encoder_cvbs)
232318ba02cSNeil Armstrong 		return -ENOMEM;
233318ba02cSNeil Armstrong 
234318ba02cSNeil Armstrong 	/* CVBS Connector Bridge */
235318ba02cSNeil Armstrong 	remote = of_graph_get_remote_node(priv->dev->of_node, 0, 0);
236318ba02cSNeil Armstrong 	if (!remote) {
23772317eaaSNeil Armstrong 		dev_info(drm->dev, "CVBS Output connector not available\n");
23872317eaaSNeil Armstrong 		return 0;
23972317eaaSNeil Armstrong 	}
24072317eaaSNeil Armstrong 
241318ba02cSNeil Armstrong 	meson_encoder_cvbs->next_bridge = of_drm_find_bridge(remote);
2427d255ddbSMiaoqian Lin 	of_node_put(remote);
243318ba02cSNeil Armstrong 	if (!meson_encoder_cvbs->next_bridge) {
244318ba02cSNeil Armstrong 		dev_err(priv->dev, "Failed to find CVBS Connector bridge\n");
245318ba02cSNeil Armstrong 		return -EPROBE_DEFER;
246318ba02cSNeil Armstrong 	}
247318ba02cSNeil Armstrong 
248318ba02cSNeil Armstrong 	/* CVBS Encoder Bridge */
249318ba02cSNeil Armstrong 	meson_encoder_cvbs->bridge.funcs = &meson_encoder_cvbs_bridge_funcs;
250318ba02cSNeil Armstrong 	meson_encoder_cvbs->bridge.of_node = priv->dev->of_node;
251318ba02cSNeil Armstrong 	meson_encoder_cvbs->bridge.type = DRM_MODE_CONNECTOR_Composite;
252318ba02cSNeil Armstrong 	meson_encoder_cvbs->bridge.ops = DRM_BRIDGE_OP_MODES;
253318ba02cSNeil Armstrong 	meson_encoder_cvbs->bridge.interlace_allowed = true;
254318ba02cSNeil Armstrong 
255318ba02cSNeil Armstrong 	drm_bridge_add(&meson_encoder_cvbs->bridge);
25672317eaaSNeil Armstrong 
25772317eaaSNeil Armstrong 	meson_encoder_cvbs->priv = priv;
25872317eaaSNeil Armstrong 
25972317eaaSNeil Armstrong 	/* Encoder */
260318ba02cSNeil Armstrong 	ret = drm_simple_encoder_init(priv->drm, &meson_encoder_cvbs->encoder,
261318ba02cSNeil Armstrong 				      DRM_MODE_ENCODER_TVDAC);
26272317eaaSNeil Armstrong 	if (ret) {
263318ba02cSNeil Armstrong 		dev_err(priv->dev, "Failed to init CVBS encoder: %d\n", ret);
26472317eaaSNeil Armstrong 		return ret;
26572317eaaSNeil Armstrong 	}
26672317eaaSNeil Armstrong 
267318ba02cSNeil Armstrong 	meson_encoder_cvbs->encoder.possible_crtcs = BIT(0);
26872317eaaSNeil Armstrong 
269318ba02cSNeil Armstrong 	/* Attach CVBS Encoder Bridge to Encoder */
270318ba02cSNeil Armstrong 	ret = drm_bridge_attach(&meson_encoder_cvbs->encoder, &meson_encoder_cvbs->bridge, NULL,
271318ba02cSNeil Armstrong 				DRM_BRIDGE_ATTACH_NO_CONNECTOR);
272318ba02cSNeil Armstrong 	if (ret) {
273318ba02cSNeil Armstrong 		dev_err(priv->dev, "Failed to attach bridge: %d\n", ret);
274318ba02cSNeil Armstrong 		return ret;
275318ba02cSNeil Armstrong 	}
276318ba02cSNeil Armstrong 
277318ba02cSNeil Armstrong 	/* Initialize & attach Bridge Connector */
278318ba02cSNeil Armstrong 	connector = drm_bridge_connector_init(priv->drm, &meson_encoder_cvbs->encoder);
279318ba02cSNeil Armstrong 	if (IS_ERR(connector)) {
280318ba02cSNeil Armstrong 		dev_err(priv->dev, "Unable to create CVBS bridge connector\n");
281318ba02cSNeil Armstrong 		return PTR_ERR(connector);
282318ba02cSNeil Armstrong 	}
283318ba02cSNeil Armstrong 	drm_connector_attach_encoder(connector, &meson_encoder_cvbs->encoder);
28472317eaaSNeil Armstrong 
28509847723SAdrián Larumbe 	priv->encoders[MESON_ENC_CVBS] = meson_encoder_cvbs;
28609847723SAdrián Larumbe 
28772317eaaSNeil Armstrong 	return 0;
28872317eaaSNeil Armstrong }
28909847723SAdrián Larumbe 
meson_encoder_cvbs_remove(struct meson_drm * priv)29009847723SAdrián Larumbe void meson_encoder_cvbs_remove(struct meson_drm *priv)
29109847723SAdrián Larumbe {
29209847723SAdrián Larumbe 	struct meson_encoder_cvbs *meson_encoder_cvbs;
29309847723SAdrián Larumbe 
29409847723SAdrián Larumbe 	if (priv->encoders[MESON_ENC_CVBS]) {
29509847723SAdrián Larumbe 		meson_encoder_cvbs = priv->encoders[MESON_ENC_CVBS];
29609847723SAdrián Larumbe 		drm_bridge_remove(&meson_encoder_cvbs->bridge);
29709847723SAdrián Larumbe 	}
29809847723SAdrián Larumbe }
299