| .. | .. |
|---|
| 32 | 32 | #include <soc/rockchip/rockchip_ipa.h> |
|---|
| 33 | 33 | #include <soc/rockchip/rockchip_opp_select.h> |
|---|
| 34 | 34 | #include <soc/rockchip/rockchip_system_monitor.h> |
|---|
| 35 | +#include <soc/rockchip/rockchip_iommu.h> |
|---|
| 35 | 36 | |
|---|
| 36 | 37 | #include "mpp_debug.h" |
|---|
| 37 | 38 | #include "mpp_iommu.h" |
|---|
| .. | .. |
|---|
| 44 | 45 | #define RKVENC_MAX_DCHS_ID 4 |
|---|
| 45 | 46 | #define RKVENC_MAX_SLICE_FIFO_LEN 256 |
|---|
| 46 | 47 | #define RKVENC_SCLR_DONE_STA BIT(2) |
|---|
| 48 | +#define RKVENC_WDG 0x38 |
|---|
| 49 | +#define TIMEOUT_MS 100 |
|---|
| 47 | 50 | |
|---|
| 48 | 51 | #define to_rkvenc_info(info) \ |
|---|
| 49 | 52 | container_of(info, struct rkvenc_hw_info, hw) |
|---|
| .. | .. |
|---|
| 127 | 130 | #define INT_STA_WBUS_ERR_STA BIT(6) |
|---|
| 128 | 131 | #define INT_STA_RBUS_ERR_STA BIT(7) |
|---|
| 129 | 132 | #define INT_STA_WDG_STA BIT(8) |
|---|
| 133 | + |
|---|
| 134 | +#define INT_STA_ERROR (INT_STA_BRSP_OTSD_STA | \ |
|---|
| 135 | + INT_STA_WBUS_ERR_STA | \ |
|---|
| 136 | + INT_STA_RBUS_ERR_STA | \ |
|---|
| 137 | + INT_STA_WDG_STA) |
|---|
| 130 | 138 | |
|---|
| 131 | 139 | #define DCHS_REG_OFFSET (0x304) |
|---|
| 132 | 140 | #define DCHS_CLASS_OFFSET (33) |
|---|
| .. | .. |
|---|
| 294 | 302 | #ifdef CONFIG_PM_DEVFREQ |
|---|
| 295 | 303 | struct rockchip_opp_info opp_info; |
|---|
| 296 | 304 | struct monitor_dev_info *mdev_info; |
|---|
| 305 | + struct opp_table *opp_table; |
|---|
| 297 | 306 | #endif |
|---|
| 298 | 307 | }; |
|---|
| 299 | 308 | |
|---|
| .. | .. |
|---|
| 1194 | 1203 | struct rkvenc_task *task = to_rkvenc_task(mpp_task); |
|---|
| 1195 | 1204 | struct rkvenc_hw_info *hw = enc->hw_info; |
|---|
| 1196 | 1205 | u32 timing_en = mpp->srv->timing_en; |
|---|
| 1206 | + u32 timeout_thd; |
|---|
| 1197 | 1207 | |
|---|
| 1198 | 1208 | mpp_debug_enter(); |
|---|
| 1199 | 1209 | |
|---|
| .. | .. |
|---|
| 1242 | 1252 | /* init current task */ |
|---|
| 1243 | 1253 | mpp->cur_task = mpp_task; |
|---|
| 1244 | 1254 | |
|---|
| 1255 | + /* |
|---|
| 1256 | + * reconfig timeout threshold. |
|---|
| 1257 | + * bit0-bit23,x1024 core clk cycles |
|---|
| 1258 | + */ |
|---|
| 1259 | + timeout_thd = mpp_read(mpp, RKVENC_WDG) & 0xff000000; |
|---|
| 1260 | + timeout_thd |= TIMEOUT_MS * clk_get_rate(enc->core_clk_info.clk) / 1024000; |
|---|
| 1261 | + mpp_write(mpp, RKVENC_WDG, timeout_thd); |
|---|
| 1262 | + |
|---|
| 1245 | 1263 | mpp_task_run_begin(mpp_task, timing_en, MPP_WORK_TIMEOUT_DELAY); |
|---|
| 1246 | 1264 | |
|---|
| 1247 | 1265 | /* Flush the register before the start the device */ |
|---|
| 1248 | 1266 | wmb(); |
|---|
| 1249 | | - |
|---|
| 1250 | 1267 | mpp_write(mpp, enc->hw_info->enc_start_base, start_val); |
|---|
| 1251 | 1268 | |
|---|
| 1252 | 1269 | mpp_task_run_end(mpp_task, timing_en); |
|---|
| .. | .. |
|---|
| 1256 | 1273 | return 0; |
|---|
| 1257 | 1274 | } |
|---|
| 1258 | 1275 | |
|---|
| 1259 | | -static void rkvenc2_read_slice_len(struct mpp_dev *mpp, struct rkvenc_task *task) |
|---|
| 1276 | +static void rkvenc2_read_slice_len(struct mpp_dev *mpp, struct rkvenc_task *task, |
|---|
| 1277 | + u32 last) |
|---|
| 1260 | 1278 | { |
|---|
| 1261 | | - u32 last = mpp_read_relaxed(mpp, 0x002c) & INT_STA_ENC_DONE_STA; |
|---|
| 1262 | 1279 | u32 sli_num = mpp_read_relaxed(mpp, RKVENC2_REG_SLICE_NUM_BASE); |
|---|
| 1263 | 1280 | union rkvenc2_slice_len_info slice_info; |
|---|
| 1264 | 1281 | u32 task_id = task->mpp_task.task_id; |
|---|
| .. | .. |
|---|
| 1298 | 1315 | struct rkvenc_hw_info *hw = enc->hw_info; |
|---|
| 1299 | 1316 | struct mpp_task *mpp_task = NULL; |
|---|
| 1300 | 1317 | struct rkvenc_task *task = NULL; |
|---|
| 1301 | | - u32 int_clear = 1; |
|---|
| 1302 | | - u32 irq_mask = 0; |
|---|
| 1318 | + u32 irq_status; |
|---|
| 1303 | 1319 | int ret = IRQ_NONE; |
|---|
| 1304 | 1320 | |
|---|
| 1305 | 1321 | mpp_debug_enter(); |
|---|
| 1306 | 1322 | |
|---|
| 1307 | | - mpp->irq_status = mpp_read(mpp, hw->int_sta_base); |
|---|
| 1308 | | - if (!mpp->irq_status) |
|---|
| 1323 | + irq_status = mpp_read(mpp, hw->int_sta_base); |
|---|
| 1324 | + |
|---|
| 1325 | + mpp_debug(DEBUG_IRQ_STATUS, "%s irq_status: %08x\n", |
|---|
| 1326 | + dev_name(mpp->dev), irq_status); |
|---|
| 1327 | + |
|---|
| 1328 | + if (!irq_status) |
|---|
| 1309 | 1329 | return ret; |
|---|
| 1330 | + |
|---|
| 1331 | + /* clear int first */ |
|---|
| 1332 | + mpp_write(mpp, hw->int_clr_base, irq_status); |
|---|
| 1333 | + |
|---|
| 1334 | + /* |
|---|
| 1335 | + * prevent watch dog irq storm. |
|---|
| 1336 | + * The encoder did not stop working when watchdog interrupt is triggered, |
|---|
| 1337 | + * it still check timeout and trigger watch dog irq. |
|---|
| 1338 | + */ |
|---|
| 1339 | + if (irq_status & INT_STA_WDG_STA) |
|---|
| 1340 | + mpp_write(mpp, hw->int_mask_base, INT_STA_WDG_STA); |
|---|
| 1310 | 1341 | |
|---|
| 1311 | 1342 | if (mpp->cur_task) { |
|---|
| 1312 | 1343 | mpp_task = mpp->cur_task; |
|---|
| 1313 | 1344 | task = to_rkvenc_task(mpp_task); |
|---|
| 1314 | 1345 | } |
|---|
| 1315 | 1346 | |
|---|
| 1316 | | - if (mpp->irq_status & INT_STA_ENC_DONE_STA) { |
|---|
| 1317 | | - if (task) { |
|---|
| 1318 | | - if (task->task_split) |
|---|
| 1319 | | - rkvenc2_read_slice_len(mpp, task); |
|---|
| 1347 | + /* 1. read slice number and slice length */ |
|---|
| 1348 | + if (task && task->task_split && |
|---|
| 1349 | + (irq_status & (INT_STA_SLC_DONE_STA | INT_STA_ENC_DONE_STA))) { |
|---|
| 1350 | + mpp_time_part_diff(mpp_task); |
|---|
| 1351 | + rkvenc2_read_slice_len(mpp, task, irq_status & INT_STA_ENC_DONE_STA); |
|---|
| 1352 | + wake_up(&mpp_task->wait); |
|---|
| 1353 | + } |
|---|
| 1320 | 1354 | |
|---|
| 1321 | | - wake_up(&mpp_task->wait); |
|---|
| 1322 | | - } |
|---|
| 1355 | + /* 2. process slice irq */ |
|---|
| 1356 | + if (irq_status & INT_STA_SLC_DONE_STA) |
|---|
| 1357 | + ret = IRQ_HANDLED; |
|---|
| 1323 | 1358 | |
|---|
| 1324 | | - irq_mask = INT_STA_ENC_DONE_STA; |
|---|
| 1325 | | - ret = IRQ_WAKE_THREAD; |
|---|
| 1326 | | - if (enc->bs_overflow) { |
|---|
| 1327 | | - mpp->irq_status |= INT_STA_BSF_OFLW_STA; |
|---|
| 1328 | | - enc->bs_overflow = 0; |
|---|
| 1329 | | - } |
|---|
| 1330 | | - } else if (mpp->irq_status & INT_STA_SLC_DONE_STA) { |
|---|
| 1331 | | - if (task && task->task_split) { |
|---|
| 1332 | | - mpp_time_part_diff(mpp_task); |
|---|
| 1333 | | - |
|---|
| 1334 | | - rkvenc2_read_slice_len(mpp, task); |
|---|
| 1335 | | - wake_up(&mpp_task->wait); |
|---|
| 1336 | | - } |
|---|
| 1337 | | - |
|---|
| 1338 | | - irq_mask = INT_STA_ENC_DONE_STA; |
|---|
| 1339 | | - int_clear = 0; |
|---|
| 1340 | | - } else if (mpp->irq_status & INT_STA_BSF_OFLW_STA) { |
|---|
| 1359 | + /* 3. process bitstream overflow */ |
|---|
| 1360 | + if (irq_status & INT_STA_BSF_OFLW_STA) { |
|---|
| 1341 | 1361 | u32 bs_rd = mpp_read(mpp, RKVENC2_REG_ADR_BSBR); |
|---|
| 1342 | 1362 | u32 bs_wr = mpp_read(mpp, RKVENC2_REG_ST_BSB); |
|---|
| 1343 | 1363 | u32 bs_top = mpp_read(mpp, RKVENC2_REG_ADR_BSBT); |
|---|
| .. | .. |
|---|
| 1349 | 1369 | bs_wr += 128; |
|---|
| 1350 | 1370 | if (bs_wr >= bs_top) |
|---|
| 1351 | 1371 | bs_wr = bs_bot; |
|---|
| 1352 | | - /* clear int first */ |
|---|
| 1353 | | - mpp_write(mpp, hw->int_clr_base, mpp->irq_status); |
|---|
| 1372 | + |
|---|
| 1354 | 1373 | /* update write addr for enc continue */ |
|---|
| 1355 | 1374 | mpp_write(mpp, RKVENC2_REG_ADR_BSBS, bs_wr); |
|---|
| 1356 | 1375 | enc->bs_overflow = 1; |
|---|
| 1357 | | - irq_mask = 0; |
|---|
| 1358 | | - int_clear = 0; |
|---|
| 1359 | | - ret = IRQ_HANDLED; |
|---|
| 1360 | | - } else { |
|---|
| 1361 | | - dev_err(mpp->dev, "found error status %08x\n", mpp->irq_status); |
|---|
| 1362 | 1376 | |
|---|
| 1363 | | - irq_mask = mpp->irq_status; |
|---|
| 1377 | + ret = IRQ_HANDLED; |
|---|
| 1378 | + } |
|---|
| 1379 | + |
|---|
| 1380 | + /* 4. process frame irq */ |
|---|
| 1381 | + if (irq_status & INT_STA_ENC_DONE_STA) { |
|---|
| 1382 | + mpp->irq_status = irq_status; |
|---|
| 1383 | + |
|---|
| 1384 | + if (enc->bs_overflow) { |
|---|
| 1385 | + mpp->irq_status |= INT_STA_BSF_OFLW_STA; |
|---|
| 1386 | + enc->bs_overflow = 0; |
|---|
| 1387 | + } |
|---|
| 1388 | + |
|---|
| 1364 | 1389 | ret = IRQ_WAKE_THREAD; |
|---|
| 1365 | 1390 | } |
|---|
| 1366 | 1391 | |
|---|
| 1367 | | - if (irq_mask) |
|---|
| 1368 | | - mpp_write(mpp, hw->int_mask_base, irq_mask); |
|---|
| 1392 | + /* 5. process error irq */ |
|---|
| 1393 | + if (irq_status & INT_STA_ERROR) { |
|---|
| 1394 | + mpp->irq_status = irq_status; |
|---|
| 1369 | 1395 | |
|---|
| 1370 | | - if (int_clear) { |
|---|
| 1371 | | - mpp_write(mpp, hw->int_clr_base, mpp->irq_status); |
|---|
| 1372 | | - udelay(5); |
|---|
| 1373 | | - mpp_write(mpp, hw->int_sta_base, 0); |
|---|
| 1396 | + dev_err(mpp->dev, "found error status %08x\n", irq_status); |
|---|
| 1397 | + |
|---|
| 1398 | + ret = IRQ_WAKE_THREAD; |
|---|
| 1374 | 1399 | } |
|---|
| 1375 | 1400 | |
|---|
| 1376 | 1401 | mpp_debug_leave(); |
|---|
| 1377 | 1402 | |
|---|
| 1378 | 1403 | return ret; |
|---|
| 1404 | +} |
|---|
| 1405 | + |
|---|
| 1406 | +static int vepu540c_irq(struct mpp_dev *mpp) |
|---|
| 1407 | +{ |
|---|
| 1408 | + return rkvenc_irq(mpp); |
|---|
| 1379 | 1409 | } |
|---|
| 1380 | 1410 | |
|---|
| 1381 | 1411 | static int rkvenc_isr(struct mpp_dev *mpp) |
|---|
| .. | .. |
|---|
| 1405 | 1435 | task->irq_status = mpp->irq_status; |
|---|
| 1406 | 1436 | |
|---|
| 1407 | 1437 | rkvenc2_update_dchs(enc, task); |
|---|
| 1408 | | - |
|---|
| 1409 | | - mpp_debug(DEBUG_IRQ_STATUS, "%s irq_status: %08x\n", |
|---|
| 1410 | | - dev_name(mpp->dev), task->irq_status); |
|---|
| 1411 | 1438 | |
|---|
| 1412 | 1439 | if (task->irq_status & enc->hw_info->err_mask) { |
|---|
| 1413 | 1440 | atomic_inc(&mpp->reset_request); |
|---|
| .. | .. |
|---|
| 1458 | 1485 | if (task->bs_buf) { |
|---|
| 1459 | 1486 | u32 bs_size = mpp_read(mpp, 0x4064); |
|---|
| 1460 | 1487 | |
|---|
| 1461 | | - mpp_dma_buf_sync(task->bs_buf, 0, bs_size / 8 + task->offset_bs, |
|---|
| 1488 | + mpp_dma_buf_sync(task->bs_buf, 0, bs_size + task->offset_bs, |
|---|
| 1462 | 1489 | DMA_FROM_DEVICE, true); |
|---|
| 1463 | 1490 | } |
|---|
| 1464 | 1491 | |
|---|
| .. | .. |
|---|
| 1785 | 1812 | if (IS_ERR(reg_table)) |
|---|
| 1786 | 1813 | return PTR_ERR(reg_table); |
|---|
| 1787 | 1814 | } |
|---|
| 1815 | + enc->opp_table = reg_table; |
|---|
| 1788 | 1816 | |
|---|
| 1789 | 1817 | clk_table = dev_pm_opp_set_clkname(dev, "clk_core"); |
|---|
| 1790 | | - if (IS_ERR(clk_table)) |
|---|
| 1791 | | - return PTR_ERR(clk_table); |
|---|
| 1818 | + if (IS_ERR(clk_table)) { |
|---|
| 1819 | + ret = PTR_ERR(clk_table); |
|---|
| 1820 | + goto put_opp_reg; |
|---|
| 1821 | + } |
|---|
| 1792 | 1822 | |
|---|
| 1793 | 1823 | rockchip_get_opp_data(rockchip_rkvenc_of_match, &enc->opp_info); |
|---|
| 1794 | 1824 | ret = rockchip_init_opp_table(dev, &enc->opp_info, "leakage", "venc"); |
|---|
| 1795 | 1825 | if (ret) { |
|---|
| 1796 | 1826 | dev_err(dev, "failed to init_opp_table\n"); |
|---|
| 1797 | | - return ret; |
|---|
| 1827 | + goto put_opp_clk; |
|---|
| 1798 | 1828 | } |
|---|
| 1799 | 1829 | |
|---|
| 1800 | 1830 | enc->mdev_info = rockchip_system_monitor_register(dev, &venc_mdevp); |
|---|
| .. | .. |
|---|
| 1803 | 1833 | enc->mdev_info = NULL; |
|---|
| 1804 | 1834 | } |
|---|
| 1805 | 1835 | |
|---|
| 1836 | + return 0; |
|---|
| 1837 | + |
|---|
| 1838 | +put_opp_clk: |
|---|
| 1839 | + dev_pm_opp_put_clkname(enc->opp_table); |
|---|
| 1840 | +put_opp_reg: |
|---|
| 1841 | + dev_pm_opp_put_regulators(enc->opp_table); |
|---|
| 1842 | + enc->opp_table = NULL; |
|---|
| 1843 | + |
|---|
| 1806 | 1844 | return ret; |
|---|
| 1807 | 1845 | } |
|---|
| 1808 | 1846 | |
|---|
| .. | .. |
|---|
| 1810 | 1848 | { |
|---|
| 1811 | 1849 | struct rkvenc_dev *enc = to_rkvenc_dev(mpp); |
|---|
| 1812 | 1850 | |
|---|
| 1813 | | - if (enc->mdev_info) |
|---|
| 1851 | + if (enc->mdev_info) { |
|---|
| 1814 | 1852 | rockchip_system_monitor_unregister(enc->mdev_info); |
|---|
| 1853 | + enc->mdev_info = NULL; |
|---|
| 1854 | + } |
|---|
| 1855 | + if (enc->opp_table) { |
|---|
| 1856 | + rockchip_uninit_opp_table(mpp->dev, &enc->opp_info); |
|---|
| 1857 | + dev_pm_opp_put_clkname(enc->opp_table); |
|---|
| 1858 | + dev_pm_opp_put_regulators(enc->opp_table); |
|---|
| 1859 | + enc->opp_table = NULL; |
|---|
| 1860 | + } |
|---|
| 1815 | 1861 | |
|---|
| 1816 | 1862 | return 0; |
|---|
| 1817 | 1863 | } |
|---|
| .. | .. |
|---|
| 1880 | 1926 | |
|---|
| 1881 | 1927 | /* safe reset */ |
|---|
| 1882 | 1928 | mpp_write(mpp, hw->int_mask_base, 0x3FF); |
|---|
| 1883 | | - mpp_write(mpp, hw->enc_clr_base, 0x1); |
|---|
| 1929 | + mpp_write(mpp, hw->enc_clr_base, 0x3); |
|---|
| 1884 | 1930 | ret = readl_relaxed_poll_timeout(mpp->reg_base + hw->int_sta_base, |
|---|
| 1885 | 1931 | rst_status, |
|---|
| 1886 | 1932 | rst_status & RKVENC_SCLR_DONE_STA, |
|---|
| .. | .. |
|---|
| 2169 | 2215 | .dump_session = rkvenc_dump_session, |
|---|
| 2170 | 2216 | }; |
|---|
| 2171 | 2217 | |
|---|
| 2218 | +static struct mpp_dev_ops vepu540c_dev_ops_v2 = { |
|---|
| 2219 | + .wait_result = rkvenc2_wait_result, |
|---|
| 2220 | + .alloc_task = rkvenc_alloc_task, |
|---|
| 2221 | + .run = rkvenc_run, |
|---|
| 2222 | + .irq = vepu540c_irq, |
|---|
| 2223 | + .isr = rkvenc_isr, |
|---|
| 2224 | + .finish = rkvenc_finish, |
|---|
| 2225 | + .result = rkvenc_result, |
|---|
| 2226 | + .free_task = rkvenc_free_task, |
|---|
| 2227 | + .ioctl = rkvenc_control, |
|---|
| 2228 | + .init_session = rkvenc_init_session, |
|---|
| 2229 | + .free_session = rkvenc_free_session, |
|---|
| 2230 | + .dump_session = rkvenc_dump_session, |
|---|
| 2231 | +}; |
|---|
| 2172 | 2232 | |
|---|
| 2173 | 2233 | static const struct mpp_dev_var rkvenc_v2_data = { |
|---|
| 2174 | 2234 | .device_type = MPP_DEVICE_RKVENC, |
|---|
| .. | .. |
|---|
| 2183 | 2243 | .hw_info = &rkvenc_540c_hw_info.hw, |
|---|
| 2184 | 2244 | .trans_info = trans_rkvenc_540c, |
|---|
| 2185 | 2245 | .hw_ops = &rkvenc_hw_ops, |
|---|
| 2186 | | - .dev_ops = &rkvenc_dev_ops_v2, |
|---|
| 2246 | + .dev_ops = &vepu540c_dev_ops_v2, |
|---|
| 2187 | 2247 | }; |
|---|
| 2188 | 2248 | |
|---|
| 2189 | 2249 | static const struct mpp_dev_var rkvenc_ccu_data = { |
|---|
| .. | .. |
|---|
| 2404 | 2464 | { |
|---|
| 2405 | 2465 | struct mpp_dev *mpp = (struct mpp_dev *)arg; |
|---|
| 2406 | 2466 | struct rkvenc_dev *enc = to_rkvenc_dev(mpp); |
|---|
| 2407 | | - struct mpp_task *mpp_task = mpp->cur_task; |
|---|
| 2467 | + struct mpp_task *mpp_task; |
|---|
| 2468 | + struct rkvenc_ccu *ccu = enc->ccu; |
|---|
| 2408 | 2469 | |
|---|
| 2470 | + if (ccu) { |
|---|
| 2471 | + struct rkvenc_dev *core = NULL, *n; |
|---|
| 2472 | + |
|---|
| 2473 | + list_for_each_entry_safe(core, n, &ccu->core_list, core_link) { |
|---|
| 2474 | + if (core->mpp.iommu_info && |
|---|
| 2475 | + (&core->mpp.iommu_info->pdev->dev == iommu_dev)) { |
|---|
| 2476 | + mpp = &core->mpp; |
|---|
| 2477 | + break; |
|---|
| 2478 | + } |
|---|
| 2479 | + } |
|---|
| 2480 | + } |
|---|
| 2481 | + mpp_task = mpp->cur_task; |
|---|
| 2409 | 2482 | dev_info(mpp->dev, "core %d page fault found dchs %08x\n", |
|---|
| 2410 | 2483 | mpp->core_id, mpp_read_relaxed(&enc->mpp, DCHS_REG_OFFSET)); |
|---|
| 2411 | 2484 | |
|---|
| 2412 | 2485 | if (mpp_task) |
|---|
| 2413 | 2486 | mpp_task_dump_mem_region(mpp, mpp_task); |
|---|
| 2487 | + |
|---|
| 2488 | + /* |
|---|
| 2489 | + * Mask iommu irq, in order for iommu not repeatedly trigger pagefault. |
|---|
| 2490 | + * Until the pagefault task finish by hw timeout. |
|---|
| 2491 | + */ |
|---|
| 2492 | + rockchip_iommu_mask_irq(mpp->dev); |
|---|
| 2414 | 2493 | |
|---|
| 2415 | 2494 | return 0; |
|---|
| 2416 | 2495 | } |
|---|
| .. | .. |
|---|
| 2455 | 2534 | ret = devm_request_threaded_irq(dev, mpp->irq, |
|---|
| 2456 | 2535 | mpp_dev_irq, |
|---|
| 2457 | 2536 | mpp_dev_isr_sched, |
|---|
| 2458 | | - IRQF_SHARED, |
|---|
| 2537 | + IRQF_ONESHOT, |
|---|
| 2459 | 2538 | dev_name(dev), mpp); |
|---|
| 2460 | 2539 | if (ret) { |
|---|
| 2461 | 2540 | dev_err(dev, "register interrupter runtime failed\n"); |
|---|