~ubuntu-branches/ubuntu/precise/linux-linaro-u8500/precise

« back to all changes in this revision

Viewing changes to drivers/video/omap2/dss/dispc.c

  • Committer: Bazaar Package Importer
  • Author(s): John Rigby, Upstream Fixes, Andy Green, John Rigby
  • Date: 2011-04-14 12:16:06 UTC
  • Revision ID: james.westby@ubuntu.com-20110414121606-b77podkyqgr2oix7
Tags: 2.6.38-1002.3
[ Upstream Fixes ]

* MUSB: shutdown: Make sure block is awake before doing shutdown
  - LP: #745737
* Fixed gpio polarity of gpio USB-phy reset.
  - LP: #747639

[ Andy Green ]

* LINARO: SAUCE: disable CONFIG_OMAP_RESET_CLOCKS
  - LP: #752900

[ John Rigby ]

* Rebase to new upstreams:
  Linux v2.6.38.1
  linaro-linux-2.6.38-upstream-29Mar2011
  Ubuntu-2.6.38-7.35
* SAUCE: OMAP4: clock: wait for module to become accessible on
  a clk enable
  - LP: #745737
* Rebase to new upstreams:
  Linux v2.6.38.2
  linaro-linux-2.6.38-upstream-5Apr2011
  Ubuntu-2.6.38-8.41
  - LP: #732842
* Update configs for device tree, dvfs and lttng
* LINARO: add building of dtb's
* LINARO: SAUCE: Disable lowest operating freqs on omap34xx
  - LP: #732912

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
#include <linux/delay.h>
33
33
#include <linux/workqueue.h>
34
34
#include <linux/hardirq.h>
 
35
#include <linux/interrupt.h>
35
36
 
36
37
#include <plat/sram.h>
37
38
#include <plat/clock.h>
72
73
#define DISPC_TIMING_H(ch)              DISPC_REG(ch != 2 ? 0x0064 : 0x0400)
73
74
#define DISPC_TIMING_V(ch)              DISPC_REG(ch != 2 ? 0x0068 : 0x0404)
74
75
#define DISPC_POL_FREQ(ch)              DISPC_REG(ch != 2 ? 0x006C : 0x0408)
75
 
/*
76
 
 * Use DISPC_DIVISORo(ch) when DISPC_DIVISOR1 or DISPC_DIVISOR2 has to be
77
 
 * configured. OMAP4 TRM uses DISPC_DIVISORo generically to refer DISPC_DIVISOR1
78
 
 * and DISPC_DIVISOR2
79
 
 */
80
76
#define DISPC_DIVISORo(ch)              DISPC_REG(ch != 2 ? 0x0070 : 0x040C)
81
77
#define DISPC_GLOBAL_ALPHA              DISPC_REG(0x0074)
82
78
#define DISPC_SIZE_DIG                  DISPC_REG(0x0078)
132
128
 
133
129
#define DISPC_VID_PRELOAD(n)            DISPC_REG(0x230 + (n)*0x04)
134
130
 
135
 
/*
136
 
 * The OMAP4 DISPC_DIVISOR1 is backward compatible to OMAP3xxx DISPC_DIVISOR.
137
 
 * However DISPC_DIVISOR is also provided in OMAP4, to control DISPC_CORE_CLK.
138
 
 * This allows DISPC_CORE_CLK to be independent of logical clock dividers (lcd)
139
 
 * of LCD1 (primary) and LCD2 (secondary) displays.
140
 
 *
141
 
 * To derive pixel clocks for Primary and Secondary LCD channels, configure the
142
 
 * lcd and pcd in DISPC_DIVISOR1 and DISPC_DIVISOR2 respectively, using the
143
 
 * DISPC_DIVISORo(ch).
144
 
 */
145
131
#define DISPC_DIVISOR                   DISPC_REG(0x0804)
146
132
 
147
133
#define DISPC_IRQ_MASK_ERROR            (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \
194
180
static struct {
195
181
        struct platform_device *pdev;
196
182
        void __iomem    *base;
 
183
        int irq;
197
184
 
198
185
        u32     fifo_size[3];
199
186
 
1021
1008
        enable_clocks(0);
1022
1009
}
1023
1010
 
 
1011
void dispc_enable_gamma_table(bool enable)
 
1012
{
 
1013
        /*
 
1014
         * This is partially implemented to support only disabling of
 
1015
         * the gamma table.
 
1016
         */
 
1017
        if (enable) {
 
1018
                DSSWARN("Gamma table enabling for TV not yet supported");
 
1019
                return;
 
1020
        }
 
1021
 
 
1022
        REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9);
 
1023
}
 
1024
 
1024
1025
static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable)
1025
1026
{
1026
1027
        u32 val;
1150
1151
        u32 val;
1151
1152
        const struct dispc_reg ac0_reg[] = { DISPC_VID_ACCU0(0),
1152
1153
                                      DISPC_VID_ACCU0(1) };
 
1154
        u8 hor_start, hor_end, vert_start, vert_end;
1153
1155
 
1154
1156
        BUG_ON(plane == OMAP_DSS_GFX);
1155
1157
 
1156
 
        val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
 
1158
        dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
 
1159
        dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
 
1160
 
 
1161
        val = FLD_VAL(vaccu, vert_start, vert_end) |
 
1162
                        FLD_VAL(haccu, hor_start, hor_end);
 
1163
 
1157
1164
        dispc_write_reg(ac0_reg[plane-1], val);
1158
1165
}
1159
1166
 
1162
1169
        u32 val;
1163
1170
        const struct dispc_reg ac1_reg[] = { DISPC_VID_ACCU1(0),
1164
1171
                                      DISPC_VID_ACCU1(1) };
 
1172
        u8 hor_start, hor_end, vert_start, vert_end;
1165
1173
 
1166
1174
        BUG_ON(plane == OMAP_DSS_GFX);
1167
1175
 
1168
 
        val = FLD_VAL(vaccu, 25, 16) | FLD_VAL(haccu, 9, 0);
 
1176
        dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
 
1177
        dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
 
1178
 
 
1179
        val = FLD_VAL(vaccu, vert_start, vert_end) |
 
1180
                        FLD_VAL(haccu, hor_start, hor_end);
 
1181
 
1169
1182
        dispc_write_reg(ac1_reg[plane-1], val);
1170
1183
}
1171
1184
 
1203
1216
        _dispc_set_fir(plane, fir_hinc, fir_vinc);
1204
1217
 
1205
1218
        l = dispc_read_reg(dispc_reg_att[plane]);
1206
 
        l &= ~((0x0f << 5) | (0x3 << 21));
1207
1219
 
 
1220
        /* RESIZEENABLE and VERTICALTAPS */
 
1221
        l &= ~((0x3 << 5) | (0x1 << 21));
1208
1222
        l |= fir_hinc ? (1 << 5) : 0;
1209
1223
        l |= fir_vinc ? (1 << 6) : 0;
1210
 
 
1211
 
        l |= hscaleup ? 0 : (1 << 7);
1212
 
        l |= vscaleup ? 0 : (1 << 8);
1213
 
 
1214
1224
        l |= five_taps ? (1 << 21) : 0;
1215
 
        l |= five_taps ? (1 << 22) : 0;
 
1225
 
 
1226
        /* VRESIZECONF and HRESIZECONF */
 
1227
        if (dss_has_feature(FEAT_RESIZECONF)) {
 
1228
                l &= ~(0x3 << 7);
 
1229
                l |= hscaleup ? 0 : (1 << 7);
 
1230
                l |= vscaleup ? 0 : (1 << 8);
 
1231
        }
 
1232
 
 
1233
        /* LINEBUFFERSPLIT */
 
1234
        if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
 
1235
                l &= ~(0x1 << 22);
 
1236
                l |= five_taps ? (1 << 22) : 0;
 
1237
        }
1216
1238
 
1217
1239
        dispc_write_reg(dispc_reg_att[plane], l);
1218
1240
 
1236
1258
static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation,
1237
1259
                bool mirroring, enum omap_color_mode color_mode)
1238
1260
{
 
1261
        bool row_repeat = false;
 
1262
        int vidrot = 0;
 
1263
 
1239
1264
        if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1240
1265
                        color_mode == OMAP_DSS_COLOR_UYVY) {
1241
 
                int vidrot = 0;
1242
1266
 
1243
1267
                if (mirroring) {
1244
1268
                        switch (rotation) {
1272
1296
                        }
1273
1297
                }
1274
1298
 
1275
 
                REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
1276
 
 
1277
1299
                if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
1278
 
                        REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
 
1300
                        row_repeat = true;
1279
1301
                else
1280
 
                        REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
1281
 
        } else {
1282
 
                REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
1283
 
                REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
 
1302
                        row_repeat = false;
1284
1303
        }
 
1304
 
 
1305
        REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
 
1306
        if (dss_has_feature(FEAT_ROWREPEATENABLE))
 
1307
                REG_FLD_MOD(dispc_reg_att[plane], row_repeat ? 1 : 0, 18, 18);
1285
1308
}
1286
1309
 
1287
1310
static int color_mode_to_bpp(enum omap_color_mode color_mode)
2332
2355
{
2333
2356
        unsigned long r = 0;
2334
2357
 
2335
 
        if (dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK)
 
2358
        switch (dss_get_dispc_clk_source()) {
 
2359
        case DSS_CLK_SRC_FCK:
2336
2360
                r = dss_clk_get_rate(DSS_CLK_FCK);
2337
 
        else
2338
 
#ifdef CONFIG_OMAP2_DSS_DSI
2339
 
                r = dsi_get_dsi1_pll_rate();
2340
 
#else
2341
 
        BUG();
2342
 
#endif
 
2361
                break;
 
2362
        case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
 
2363
                r = dsi_get_pll_hsdiv_dispc_rate();
 
2364
                break;
 
2365
        default:
 
2366
                BUG();
 
2367
        }
 
2368
 
2343
2369
        return r;
2344
2370
}
2345
2371
 
2353
2379
 
2354
2380
        lcd = FLD_GET(l, 23, 16);
2355
2381
 
2356
 
        r = dispc_fclk_rate();
 
2382
        switch (dss_get_lcd_clk_source(channel)) {
 
2383
        case DSS_CLK_SRC_FCK:
 
2384
                r = dss_clk_get_rate(DSS_CLK_FCK);
 
2385
                break;
 
2386
        case DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
 
2387
                r = dsi_get_pll_hsdiv_dispc_rate();
 
2388
                break;
 
2389
        default:
 
2390
                BUG();
 
2391
        }
2357
2392
 
2358
2393
        return r / lcd;
2359
2394
}
2360
2395
 
2361
2396
unsigned long dispc_pclk_rate(enum omap_channel channel)
2362
2397
{
2363
 
        int lcd, pcd;
 
2398
        int pcd;
2364
2399
        unsigned long r;
2365
2400
        u32 l;
2366
2401
 
2367
2402
        l = dispc_read_reg(DISPC_DIVISORo(channel));
2368
2403
 
2369
 
        lcd = FLD_GET(l, 23, 16);
2370
2404
        pcd = FLD_GET(l, 7, 0);
2371
2405
 
2372
 
        r = dispc_fclk_rate();
 
2406
        r = dispc_lclk_rate(channel);
2373
2407
 
2374
 
        return r / lcd / pcd;
 
2408
        return r / pcd;
2375
2409
}
2376
2410
 
2377
2411
void dispc_dump_clocks(struct seq_file *s)
2378
2412
{
2379
2413
        int lcd, pcd;
 
2414
        u32 l;
 
2415
        enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
 
2416
        enum dss_clk_source lcd_clk_src;
2380
2417
 
2381
2418
        enable_clocks(1);
2382
2419
 
2383
2420
        seq_printf(s, "- DISPC -\n");
2384
2421
 
2385
 
        seq_printf(s, "dispc fclk source = %s\n",
2386
 
                        dss_get_dispc_clk_source() == DSS_SRC_DSS1_ALWON_FCLK ?
2387
 
                        "dss1_alwon_fclk" : "dsi1_pll_fclk");
 
2422
        seq_printf(s, "dispc fclk source = %s (%s)\n",
 
2423
                        dss_get_generic_clk_source_name(dispc_clk_src),
 
2424
                        dss_feat_get_clk_source_name(dispc_clk_src));
2388
2425
 
2389
2426
        seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
2390
2427
 
 
2428
        if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
 
2429
                seq_printf(s, "- DISPC-CORE-CLK -\n");
 
2430
                l = dispc_read_reg(DISPC_DIVISOR);
 
2431
                lcd = FLD_GET(l, 23, 16);
 
2432
 
 
2433
                seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
 
2434
                                (dispc_fclk_rate()/lcd), lcd);
 
2435
        }
2391
2436
        seq_printf(s, "- LCD1 -\n");
2392
2437
 
 
2438
        lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD);
 
2439
 
 
2440
        seq_printf(s, "lcd1_clk source = %s (%s)\n",
 
2441
                dss_get_generic_clk_source_name(lcd_clk_src),
 
2442
                dss_feat_get_clk_source_name(lcd_clk_src));
 
2443
 
2393
2444
        dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd);
2394
2445
 
2395
2446
        seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
2399
2450
        if (dss_has_feature(FEAT_MGR_LCD2)) {
2400
2451
                seq_printf(s, "- LCD2 -\n");
2401
2452
 
 
2453
                lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2);
 
2454
 
 
2455
                seq_printf(s, "lcd2_clk source = %s (%s)\n",
 
2456
                        dss_get_generic_clk_source_name(lcd_clk_src),
 
2457
                        dss_feat_get_clk_source_name(lcd_clk_src));
 
2458
 
2402
2459
                dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd);
2403
2460
 
2404
2461
                seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
2812
2869
                break;
2813
2870
        }
2814
2871
 
 
2872
        if (ret)
 
2873
                goto err;
 
2874
 
2815
2875
        _omap_dispc_set_irqs();
2816
2876
 
2817
2877
        spin_unlock_irqrestore(&dispc.irq_lock, flags);
2887
2947
 * but we presume they are on because we got an IRQ. However,
2888
2948
 * an irq handler may turn the clocks off, so we may not have
2889
2949
 * clock later in the function. */
2890
 
void dispc_irq_handler(void)
 
2950
static irqreturn_t omap_dispc_irq_handler(int irq, void *arg)
2891
2951
{
2892
2952
        int i;
2893
 
        u32 irqstatus;
 
2953
        u32 irqstatus, irqenable;
2894
2954
        u32 handledirqs = 0;
2895
2955
        u32 unhandled_errors;
2896
2956
        struct omap_dispc_isr_data *isr_data;
2899
2959
        spin_lock(&dispc.irq_lock);
2900
2960
 
2901
2961
        irqstatus = dispc_read_reg(DISPC_IRQSTATUS);
 
2962
        irqenable = dispc_read_reg(DISPC_IRQENABLE);
 
2963
 
 
2964
        /* IRQ is not for us */
 
2965
        if (!(irqstatus & irqenable)) {
 
2966
                spin_unlock(&dispc.irq_lock);
 
2967
                return IRQ_NONE;
 
2968
        }
2902
2969
 
2903
2970
#ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS
2904
2971
        spin_lock(&dispc.irq_stats_lock);
2950
3017
        }
2951
3018
 
2952
3019
        spin_unlock(&dispc.irq_lock);
 
3020
 
 
3021
        return IRQ_HANDLED;
2953
3022
}
2954
3023
 
2955
3024
static void dispc_error_worker(struct work_struct *work)
3353
3422
static int omap_dispchw_probe(struct platform_device *pdev)
3354
3423
{
3355
3424
        u32 rev;
 
3425
        int r = 0;
3356
3426
        struct resource *dispc_mem;
3357
3427
 
3358
3428
        dispc.pdev = pdev;
3369
3439
        dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
3370
3440
        if (!dispc_mem) {
3371
3441
                DSSERR("can't get IORESOURCE_MEM DISPC\n");
3372
 
                return -EINVAL;
 
3442
                r = -EINVAL;
 
3443
                goto fail0;
3373
3444
        }
3374
3445
        dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem));
3375
3446
        if (!dispc.base) {
3376
3447
                DSSERR("can't ioremap DISPC\n");
3377
 
                return -ENOMEM;
 
3448
                r = -ENOMEM;
 
3449
                goto fail0;
 
3450
        }
 
3451
        dispc.irq = platform_get_irq(dispc.pdev, 0);
 
3452
        if (dispc.irq < 0) {
 
3453
                DSSERR("platform_get_irq failed\n");
 
3454
                r = -ENODEV;
 
3455
                goto fail1;
 
3456
        }
 
3457
 
 
3458
        r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED,
 
3459
                "OMAP DISPC", dispc.pdev);
 
3460
        if (r < 0) {
 
3461
                DSSERR("request_irq failed\n");
 
3462
                goto fail1;
3378
3463
        }
3379
3464
 
3380
3465
        enable_clocks(1);
3392
3477
        enable_clocks(0);
3393
3478
 
3394
3479
        return 0;
 
3480
fail1:
 
3481
        iounmap(dispc.base);
 
3482
fail0:
 
3483
        return r;
3395
3484
}
3396
3485
 
3397
3486
static int omap_dispchw_remove(struct platform_device *pdev)
3398
3487
{
 
3488
        free_irq(dispc.irq, dispc.pdev);
3399
3489
        iounmap(dispc.base);
3400
3490
        return 0;
3401
3491
}
3404
3494
        .probe          = omap_dispchw_probe,
3405
3495
        .remove         = omap_dispchw_remove,
3406
3496
        .driver         = {
3407
 
                .name   = "omap_dispc",
 
3497
                .name   = "omapdss_dispc",
3408
3498
                .owner  = THIS_MODULE,
3409
3499
        },
3410
3500
};