Mercurial > mplayer.hg
comparison drivers/radeon/radeonfb.c @ 2142:8939341c5187
Some fixes
author | nick |
---|---|
date | Tue, 09 Oct 2001 07:44:10 +0000 |
parents | f13d61fde30d |
children | 81f16b270b8b |
comparison
equal
deleted
inserted
replaced
2141:fa62c11857e8 | 2142:8939341c5187 |
---|---|
65 #include <linux/console.h> | 65 #include <linux/console.h> |
66 #include <linux/selection.h> | 66 #include <linux/selection.h> |
67 #include <linux/ioport.h> | 67 #include <linux/ioport.h> |
68 #include <linux/init.h> | 68 #include <linux/init.h> |
69 #include <linux/pci.h> | 69 #include <linux/pci.h> |
70 #include <linux/unistd.h> | |
70 | 71 |
71 #include <asm/io.h> | 72 #include <asm/io.h> |
72 | 73 |
73 #include <video/fbcon.h> | 74 #include <video/fbcon.h> |
74 #include <video/fbcon-cfb8.h> | 75 #include <video/fbcon-cfb8.h> |
1499 * mode corruption. | 1500 * mode corruption. |
1500 if (save->bus_cntl & (BUS_READ_BURST)) | 1501 if (save->bus_cntl & (BUS_READ_BURST)) |
1501 save->bus_cntl |= BUS_RD_DISCARD_EN; | 1502 save->bus_cntl |= BUS_RD_DISCARD_EN; |
1502 */ | 1503 */ |
1503 } | 1504 } |
1504 #if 0 | 1505 |
1505 static int radeon_init_crtc_regs(struct radeonfb_info *rinfo, | 1506 static int radeon_init_crtc_regs(struct radeonfb_info *rinfo, |
1506 struct radeon_regs *save, | 1507 struct radeon_regs *save, |
1507 struct fb_var_screeninfo *mode) | 1508 struct fb_var_screeninfo *mode) |
1508 { | 1509 { |
1509 int format; | |
1510 int hsync_start; | |
1511 int hsync_wid; | |
1512 int hsync_fudge; | |
1513 int vsync_wid; | |
1514 int bytpp; | |
1515 int hsync_fudge_default[] = { 0x00, 0x12, 0x09, 0x09, 0x06, 0x05 }; | |
1516 int hsync_fudge_fp[] = { 0x02, 0x02, 0x00, 0x00, 0x05, 0x05 }; | |
1517 int prim_mon; | |
1518 int hTotal, vTotal, hSyncStart, hSyncEnd; | |
1519 int vSyncStart, vSyncEnd; | |
1520 RTRACE("radeonfb: radeon_init_crtc_regs is called\n"); | |
1521 | |
1522 switch (mode->bits_per_pixel) { | |
1523 case 8: format = 2; bytpp = 1; break; | |
1524 case 16: format = 4; bytpp = 2; break; /* 565 */ | |
1525 case 24: format = 5; bytpp = 3; break; /* RGB */ | |
1526 case 32: format = 6; bytpp = 4; break; /* xRGB */ | |
1527 default: | |
1528 printk("radeonfb: Unsupported pixel depth (%d)\n", mode->bits_per_pixel); | |
1529 return 0; | |
1530 } | |
1531 prim_mon = PRIMARY_MONITOR(rinfo); | |
1532 if ((prim_mon == MT_DFP) || (prim_mon == MT_LCD)) | |
1533 hsync_fudge = hsync_fudge_fp[format-1]; | |
1534 else | |
1535 hsync_fudge = hsync_fudge_default[format-1]; | |
1536 | |
1537 save->crtc_gen_cntl = (CRTC_EXT_DISP_EN | |
1538 | CRTC_EN | |
1539 | (format << 8) | |
1540 /* | CRTC_DBL_SCAN_EN*/); | |
1541 | |
1542 if((prim_mon == MT_DFP) || (prim_mon == MT_LCD)) | |
1543 { | |
1544 save->crtc_ext_cntl = VGA_ATI_LINEAR | | |
1545 XCRT_CNT_EN; | |
1546 save->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN | | |
1547 CRTC_INTERLACE_EN); | |
1548 } | |
1549 else | |
1550 save->crtc_ext_cntl = VGA_ATI_LINEAR | | |
1551 XCRT_CNT_EN | | |
1552 CRTC_CRT_ON; | |
1553 | |
1554 save->dac_cntl = (DAC_MASK_ALL | |
1555 | DAC_VGA_ADR_EN | |
1556 | DAC_8BIT_EN); | |
1557 | |
1558 rinfo->xres = mode->xres; | |
1559 rinfo->yres = mode->yres; | |
1560 rinfo->pixclock = mode->pixclock; | |
1561 | |
1562 hSyncStart = mode->xres + mode->right_margin; | |
1563 hSyncEnd = hSyncStart + mode->hsync_len; | |
1564 hTotal = hSyncEnd + mode->left_margin; | |
1565 | |
1566 vSyncStart = mode->yres + mode->lower_margin; | |
1567 vSyncEnd = vSyncStart + mode->vsync_len; | |
1568 vTotal = vSyncEnd + mode->upper_margin; | |
1569 | |
1570 if(((prim_mon == MT_DFP) || (prim_mon == MT_LCD))) | |
1571 { | |
1572 if(rinfo->PanelXRes < mode->xres) | |
1573 rinfo->xres = mode->xres = rinfo->PanelXRes; | |
1574 if(rinfo->PanelYRes < mode->yres) | |
1575 rinfo->yres = mode->yres = rinfo->PanelYRes; | |
1576 hTotal = mode->xres + rinfo->HBlank + mode->left_margin; | |
1577 hSyncStart = mode->xres + rinfo->HOverPlus + mode->right_margin; | |
1578 hSyncEnd = hSyncStart + rinfo->HSyncWidth + mode->hsync_len; | |
1579 vTotal = mode->yres + rinfo->VBlank + mode->upper_margin; | |
1580 vSyncStart = mode->yres + rinfo->VOverPlus + mode->lower_margin; | |
1581 vSyncEnd = vSyncStart + rinfo->VSyncWidth + mode->vsync_len; | |
1582 } | |
1583 | |
1584 save->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | |
1585 | ((((mode->xres / 8) - 1) & 0x1ff) << 16)); | |
1586 | |
1587 hsync_wid = (hSyncEnd - hSyncStart) / 8; | |
1588 if (!hsync_wid) hsync_wid = 1; | |
1589 if (hsync_wid > 0x3f) hsync_wid = 0x3f; | |
1590 hsync_start = hSyncStart - 8 + hsync_fudge; | |
1591 | |
1592 save->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | |
1593 | (hsync_wid << 16) | |
1594 | ((mode->sync & FB_SYNC_HOR_HIGH_ACT) | |
1595 ? 0 | |
1596 : CRTC_H_SYNC_POL)); | |
1597 | |
1598 /* This works for double scan mode. */ | |
1599 save->crtc_v_total_disp = (((vTotal - 1) & 0xffff) | |
1600 | ((mode->yres - 1) << 16)); | |
1601 | |
1602 vsync_wid = vSyncEnd - vSyncStart; | |
1603 if (!vsync_wid) vsync_wid = 1; | |
1604 if (vsync_wid > 0x1f) vsync_wid = 0x1f; | |
1605 | |
1606 save->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | |
1607 | (vsync_wid << 16) | |
1608 | ((mode->sync & FB_SYNC_VERT_HIGH_ACT) | |
1609 ? 0 | |
1610 : CRTC_V_SYNC_POL)); | |
1611 | |
1612 save->crtc_offset = 0; | |
1613 save->crtc_offset_cntl = 0; | |
1614 | |
1615 save->crtc_pitch = ((mode->xres * bytpp) + | |
1616 ((mode->bits_per_pixel) - 1)) / | |
1617 (mode->bits_per_pixel); | |
1618 save->crtc_pitch |= save->crtc_pitch << 16; | |
1619 | |
1620 save->xres = mode->xres; | |
1621 save->yres = mode->yres; | |
1622 | |
1623 RTRACE("radeonfb: radeon_init_crtc_regs returns SUCCESS\n"); | |
1624 return 1; | |
1625 } | |
1626 #endif | |
1627 static int radeon_init_crtc_regs(struct radeonfb_info *rinfo, | |
1628 struct radeon_regs *save, | |
1629 struct fb_var_screeninfo *mode) | |
1630 { | |
1631 int hTotal, vTotal, hSyncStart, hSyncEnd, | 1510 int hTotal, vTotal, hSyncStart, hSyncEnd, |
1632 hSyncPol, vSyncStart, vSyncEnd, vSyncPol, cSync; | 1511 vSyncStart, vSyncEnd, cSync; |
1633 u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5}; | 1512 u8 hsync_adj_tab[] = {0, 0x12, 9, 9, 6, 5}; |
1634 u8 hsync_fudge_fp[] = { 2, 2, 0, 0, 5, 5 }; | 1513 u8 hsync_fudge_fp[] = { 2, 2, 0, 0, 5, 5 }; |
1635 u32 sync, h_sync_pol, v_sync_pol; | 1514 u32 sync; |
1636 int format = 0; | 1515 int format = 0; |
1637 int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; | 1516 int hsync_start, hsync_fudge, bytpp, hsync_wid, vsync_wid; |
1638 int prim_mon; | 1517 int prim_mon; |
1639 | 1518 |
1640 prim_mon = PRIMARY_MONITOR(rinfo); | 1519 prim_mon = PRIMARY_MONITOR(rinfo); |
1664 vSyncStart = mode->yres + rinfo->VOverPlus + mode->lower_margin; | 1543 vSyncStart = mode->yres + rinfo->VOverPlus + mode->lower_margin; |
1665 vSyncEnd = vSyncStart + rinfo->VSyncWidth + mode->vsync_len; | 1544 vSyncEnd = vSyncStart + rinfo->VSyncWidth + mode->vsync_len; |
1666 } | 1545 } |
1667 | 1546 |
1668 sync = mode->sync; | 1547 sync = mode->sync; |
1669 h_sync_pol = sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; | |
1670 v_sync_pol = sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; | |
1671 | 1548 |
1672 RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n", | 1549 RTRACE("hStart = %d, hEnd = %d, hTotal = %d\n", |
1673 hSyncStart, hSyncEnd, hTotal); | 1550 hSyncStart, hSyncEnd, hTotal); |
1674 RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n", | 1551 RTRACE("vStart = %d, vEnd = %d, vTotal = %d\n", |
1675 vSyncStart, vSyncEnd, vTotal); | 1552 vSyncStart, vSyncEnd, vTotal); |
1683 vsync_wid = mode->vsync_len; | 1560 vsync_wid = mode->vsync_len; |
1684 if (vsync_wid == 0) | 1561 if (vsync_wid == 0) |
1685 vsync_wid = 1; | 1562 vsync_wid = 1; |
1686 else if (vsync_wid > 0x1f) /* max */ | 1563 else if (vsync_wid > 0x1f) /* max */ |
1687 vsync_wid = 0x1f; | 1564 vsync_wid = 0x1f; |
1688 | |
1689 hSyncPol = mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 : 1; | |
1690 vSyncPol = mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 : 1; | |
1691 | 1565 |
1692 cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; | 1566 cSync = mode->sync & FB_SYNC_COMP_HIGH_ACT ? (1 << 4) : 0; |
1693 | 1567 |
1694 switch (mode->bits_per_pixel) { | 1568 switch (mode->bits_per_pixel) { |
1695 case 8: | 1569 case 8: |
1706 break; | 1580 break; |
1707 case 32: | 1581 case 32: |
1708 format = DST_32BPP; | 1582 format = DST_32BPP; |
1709 bytpp = 4; | 1583 bytpp = 4; |
1710 break; | 1584 break; |
1585 default: | |
1586 printk("radeonfb: Unsupported pixel depth (%d)\n", mode->bits_per_pixel); | |
1587 return 0; | |
1711 } | 1588 } |
1712 | 1589 |
1713 if ((prim_mon == MT_DFP) || (prim_mon == MT_LCD)) | 1590 if ((prim_mon == MT_DFP) || (prim_mon == MT_LCD)) |
1714 hsync_fudge = hsync_fudge_fp[format-1]; | 1591 hsync_fudge = hsync_fudge_fp[format-1]; |
1715 else | 1592 else |
1719 save->crtc_gen_cntl = (CRTC_EXT_DISP_EN | 1596 save->crtc_gen_cntl = (CRTC_EXT_DISP_EN |
1720 | CRTC_EN | 1597 | CRTC_EN |
1721 | (format << 8) | 1598 | (format << 8) |
1722 /* | CRTC_DBL_SCAN_EN*/); | 1599 /* | CRTC_DBL_SCAN_EN*/); |
1723 | 1600 |
1724 if((prim_mon == MT_DFP) || (prim_mon == MT_LCD)) | 1601 if((prim_mon == MT_DFP) || (prim_mon == MT_LCD)) { |
1725 { | |
1726 save->crtc_ext_cntl = VGA_ATI_LINEAR | | 1602 save->crtc_ext_cntl = VGA_ATI_LINEAR | |
1727 XCRT_CNT_EN; | 1603 XCRT_CNT_EN; |
1728 save->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN | | 1604 save->crtc_gen_cntl &= ~(CRTC_DBL_SCAN_EN | |
1729 CRTC_INTERLACE_EN); | 1605 CRTC_INTERLACE_EN); |
1730 } | 1606 } |
1731 else | 1607 else |
1732 save->crtc_ext_cntl = VGA_ATI_LINEAR | | 1608 save->crtc_ext_cntl = VGA_ATI_LINEAR | |
1733 XCRT_CNT_EN | | 1609 XCRT_CNT_EN | |
1734 CRTC_CRT_ON; | 1610 CRTC_CRT_ON; |
1735 | 1611 |
1736 save->dac_cntl = (DAC_MASK_ALL | 1612 save->dac_cntl = (DAC_MASK_ALL |
1737 | DAC_VGA_ADR_EN | 1613 | DAC_VGA_ADR_EN |
1738 | DAC_8BIT_EN); | 1614 | DAC_8BIT_EN); |
1739 | 1615 |
1740 save->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | | 1616 save->crtc_h_total_disp = ((((hTotal / 8) - 1) & 0x3ff) | |
1741 ((((mode->xres / 8) - 1) & 0x1ff) << 16)); | 1617 ((((mode->xres / 8) - 1) & 0x1ff) << 16)); |
1742 | 1618 |
1743 save->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) | | |
1744 (hsync_wid << 16) | (h_sync_pol << 23)); | |
1745 | |
1746 save->crtc_v_total_disp = ((vTotal - 1) & 0xffff) | | 1619 save->crtc_v_total_disp = ((vTotal - 1) & 0xffff) | |
1747 ((mode->yres - 1) << 16); | 1620 ((mode->yres - 1) << 16); |
1748 | 1621 |
1749 save->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | | 1622 save->crtc_h_sync_strt_wid = ((hsync_start & 0x1fff) |
1750 (vsync_wid << 16) | (v_sync_pol << 23)); | 1623 | (hsync_wid << 16) |
1751 | 1624 | (mode->sync & FB_SYNC_HOR_HIGH_ACT ? 0 |
1752 save->crtc_pitch = (mode->xres >> 3); | 1625 : CRTC_H_SYNC_POL)); |
1626 | |
1627 save->crtc_v_sync_strt_wid = (((vSyncStart - 1) & 0xfff) | |
1628 | (vsync_wid << 16) | |
1629 | (mode->sync & FB_SYNC_VERT_HIGH_ACT ? 0 | |
1630 : CRTC_V_SYNC_POL)); | |
1631 | |
1632 save->crtc_pitch = ((mode->xres * bytpp) + | |
1633 ((mode->bits_per_pixel) - 1)) / | |
1634 (mode->bits_per_pixel); | |
1635 save->crtc_pitch |= save->crtc_pitch<<16; | |
1753 | 1636 |
1754 #if defined(__BIG_ENDIAN) | 1637 #if defined(__BIG_ENDIAN) |
1755 save->surface_cntl = SURF_TRANSLATION_DIS; | 1638 save->surface_cntl = SURF_TRANSLATION_DIS; |
1756 switch (mode->bits_per_pixel) { | 1639 switch (mode->bits_per_pixel) { |
1757 case 16: | 1640 case 16: |
1766 | 1649 |
1767 rinfo->pitch = ((mode->xres * ((mode->bits_per_pixel + 1) / 8) + 0x3f) | 1650 rinfo->pitch = ((mode->xres * ((mode->bits_per_pixel + 1) / 8) + 0x3f) |
1768 & ~(0x3f)) / 64; | 1651 & ~(0x3f)) / 64; |
1769 | 1652 |
1770 RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", | 1653 RTRACE("h_total_disp = 0x%x\t hsync_strt_wid = 0x%x\n", |
1771 newmode.crtc_h_total_disp, newmode.crtc_h_sync_strt_wid); | 1654 save->crtc_h_total_disp, save->crtc_h_sync_strt_wid); |
1772 RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", | 1655 RTRACE("v_total_disp = 0x%x\t vsync_strt_wid = 0x%x\n", |
1773 newmode.crtc_v_total_disp, newmode.crtc_v_sync_strt_wid); | 1656 save->crtc_v_total_disp, save->crtc_v_sync_strt_wid); |
1774 | 1657 |
1775 save->xres = mode->xres; | 1658 save->xres = mode->xres; |
1776 save->yres = mode->yres; | 1659 save->yres = mode->yres; |
1777 | 1660 |
1778 save->crtc_offset = 0; | 1661 save->crtc_offset = 0; |
2001 save->ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16); | 1884 save->ppll_div_3 = rinfo->fb_div | (post_div->bitvalue << 16); |
2002 save->htotal_cntl = 0; | 1885 save->htotal_cntl = 0; |
2003 | 1886 |
2004 RTRACE("post div = 0x%x\n", rinfo->post_div); | 1887 RTRACE("post div = 0x%x\n", rinfo->post_div); |
2005 RTRACE("fb_div = 0x%x\n", rinfo->fb_div); | 1888 RTRACE("fb_div = 0x%x\n", rinfo->fb_div); |
2006 RTRACE("ppll_div_3 = 0x%x\n", newmode.ppll_div_3); | 1889 RTRACE("ppll_div_3 = 0x%x\n", save->ppll_div_3); |
2007 } | 1890 } |
2008 | 1891 |
2009 static void radeon_init_pll2_regs(struct radeonfb_info *rinfo, | 1892 static void radeon_init_pll2_regs(struct radeonfb_info *rinfo, |
2010 struct radeon_regs *save, | 1893 struct radeon_regs *save, |
2011 struct fb_var_screeninfo *mode) | 1894 struct fb_var_screeninfo *mode) |
2736 val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | | 2619 val &= ~(CRTC_DISPLAY_DIS | CRTC_HSYNC_DIS | |
2737 CRTC_VSYNC_DIS); | 2620 CRTC_VSYNC_DIS); |
2738 | 2621 |
2739 switch (blank) { | 2622 switch (blank) { |
2740 case VESA_NO_BLANKING: | 2623 case VESA_NO_BLANKING: |
2624 if(DUAL_MONITOR(rinfo)) { | |
2625 OUTREGP(CRTC2_GEN_CNTL, | |
2626 0, | |
2627 ~(CRTC2_DISP_DIS | | |
2628 CRTC2_VSYNC_DIS | | |
2629 CRTC2_HSYNC_DIS)); | |
2630 } | |
2631 switch(PRIMARY_MONITOR(rinfo)) { | |
2632 case MT_LCD: | |
2633 OUTREGP(LVDS_GEN_CNTL, 0, | |
2634 ~LVDS_DISPLAY_DIS); | |
2635 case MT_CRT: | |
2636 case MT_DFP: | |
2637 OUTREGP(CRTC_EXT_CNTL, | |
2638 CRTC_CRT_ON, | |
2639 ~(CRTC_DISPLAY_DIS | | |
2640 CRTC_VSYNC_DIS | | |
2641 CRTC_HSYNC_DIS)); | |
2642 break; | |
2643 case MT_NONE: | |
2644 default: | |
2645 break; | |
2646 | |
2647 } | |
2741 break; | 2648 break; |
2742 case VESA_VSYNC_SUSPEND: | 2649 case VESA_VSYNC_SUSPEND: |
2743 val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS); | 2650 val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS); |
2744 break; | 2651 break; |
2745 case VESA_HSYNC_SUSPEND: | 2652 case VESA_HSYNC_SUSPEND: |
2748 case VESA_POWERDOWN: | 2655 case VESA_POWERDOWN: |
2749 val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | | 2656 val |= (CRTC_DISPLAY_DIS | CRTC_VSYNC_DIS | |
2750 CRTC_HSYNC_DIS); | 2657 CRTC_HSYNC_DIS); |
2751 break; | 2658 break; |
2752 } | 2659 } |
2753 if(blank == VESA_NO_BLANKING && rinfo->hasCRTC2) | 2660 if(blank != VESA_NO_BLANKING) OUTREG(CRTC_EXT_CNTL, val); |
2754 OUTREGP(CRTC_EXT_CNTL,CRTC_CRT_ON, val); | |
2755 else OUTREG(CRTC_EXT_CNTL, val); | |
2756 } | 2661 } |
2757 | 2662 |
2758 | 2663 |
2759 | 2664 |
2760 static int radeon_get_cmap_len (const struct fb_var_screeninfo *var) | 2665 static int radeon_get_cmap_len (const struct fb_var_screeninfo *var) |
3089 OUTREG(LVDS_GEN_CNTL, restore->lvds_gen_cntl); | 2994 OUTREG(LVDS_GEN_CNTL, restore->lvds_gen_cntl); |
3090 } | 2995 } |
3091 } | 2996 } |
3092 else { | 2997 else { |
3093 if (restore->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) { | 2998 if (restore->lvds_gen_cntl & (LVDS_ON | LVDS_BLON)) { |
3094 #if 0 | 2999 udelay(rinfo->PanelPwrDly * 1000); |
3095 /* TODO it later */ | |
3096 usleep(rinfo->PanelPwrDly * 1000); | |
3097 #endif | |
3098 OUTREG(LVDS_GEN_CNTL, restore->lvds_gen_cntl); | 3000 OUTREG(LVDS_GEN_CNTL, restore->lvds_gen_cntl); |
3099 } | 3001 } |
3100 else { | 3002 else { |
3101 OUTREG(LVDS_GEN_CNTL, | 3003 OUTREG(LVDS_GEN_CNTL, |
3102 restore->lvds_gen_cntl | LVDS_BLON); | 3004 restore->lvds_gen_cntl | LVDS_BLON); |
3103 #if 0 | 3005 udelay(rinfo->PanelPwrDly * 1000); |
3104 /* TODO it later */ | |
3105 usleep(rinfo->PanelPwrDly * 1000); | |
3106 #endif | |
3107 OUTREG(LVDS_GEN_CNTL, restore->lvds_gen_cntl); | 3006 OUTREG(LVDS_GEN_CNTL, restore->lvds_gen_cntl); |
3108 } | 3007 } |
3109 } | 3008 } |
3110 } | 3009 } |
3111 | 3010 |